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

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

Client-GLI was noticeably slow compared to GLI when swapping between format statements or when typing anything into a format statement. The cause was my own mistake from 9 years ago (commit revision 24424) when I didn't know that the CollectionManager.built() operation was an expensive remote call in the case of IsGsdlRemote. This function was being called to determine if the previewbutton should really be available (enabled or disabled) so that the user could not accidentally attempt to preview an unbuilt collection. However, I must not have realised back then that the previewbutton was being set this way at every character added into the Format statements editor, as well as when swapping between one format statement and another. As a result, all of such user action was being severely delayed when isGsdlRemote was true. Fixed this now by adding a function CollectionManager.previewAvailable() that returns the last known result of the built() call. Client-GLI's format pane is now thankfully so much faster, rather than a pain to use.

  • Property svn:keywords set to Author Date Id Revision
File size: 99.7 KB
Line 
1/**
2 *#########################################################################
3 *
4 * A component of the Gatherer application, part of the Greenstone digital
5 * library suite from the New Zealand Digital Library Project at the
6 * University of Waikato, New Zealand.
7 *
8 * <BR><BR>
9 *
10 * Author: John Thompson, Greenstone Digital Library, University of Waikato
11 *
12 * <BR><BR>
13 *
14 * Copyright (C) 1999 New Zealand Digital Library Project
15 *
16 * <BR><BR>
17 *
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or
21 * (at your option) any later version.
22 *
23 * <BR><BR>
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * <BR><BR>
31 *
32 * You should have received a copy of the GNU General Public License
33 * along with this program; if not, write to the Free Software
34 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
35 *########################################################################
36 */
37package org.greenstone.gatherer.collection;
38
39import java.io.*;
40import java.util.*;
41import javax.swing.*;
42import javax.swing.event.*;
43import javax.swing.filechooser.FileSystemView;
44import javax.swing.tree.*;
45import org.greenstone.gatherer.Configuration;
46import org.greenstone.gatherer.DebugStream;
47import org.greenstone.gatherer.Dictionary;
48import org.greenstone.gatherer.Gatherer;
49import org.greenstone.gatherer.cdm.CollectionDesignManager;
50import org.greenstone.gatherer.cdm.CollectionMeta;
51import org.greenstone.gatherer.cdm.CollectionMetaManager;
52import org.greenstone.gatherer.cdm.CommandTokenizer;
53import org.greenstone.gatherer.cdm.BuildTypeManager;
54import org.greenstone.gatherer.cdm.CollectionConfiguration;
55import org.greenstone.gatherer.greenstone.Classifiers;
56import org.greenstone.gatherer.greenstone.LocalGreenstone;
57import org.greenstone.gatherer.greenstone.LocalLibraryServer;
58import org.greenstone.gatherer.greenstone.Plugins;
59import org.greenstone.gatherer.greenstone3.ServletConfiguration;
60import org.greenstone.gatherer.gui.LockFileDialog;
61import org.greenstone.gatherer.gui.ModalProgressPopup;
62import org.greenstone.gatherer.gui.TestingPreparation;
63import org.greenstone.gatherer.gui.WarningDialog;
64import org.greenstone.gatherer.metadata.DocXMLFileManager;
65import org.greenstone.gatherer.metadata.FilenameEncoding;
66import org.greenstone.gatherer.metadata.MetadataChangedListener;
67import org.greenstone.gatherer.metadata.MetadataSet;
68import org.greenstone.gatherer.metadata.MetadataSetManager;
69import org.greenstone.gatherer.metadata.MetadataXMLFileManager;
70import org.greenstone.gatherer.metadata.ProfileXMLFileManager;
71import org.greenstone.gatherer.remote.RemoteGreenstoneServer;
72import org.greenstone.gatherer.shell.GShell;
73import org.greenstone.gatherer.shell.GShellEvent;
74import org.greenstone.gatherer.shell.GShellListener;
75import org.greenstone.gatherer.shell.GShellProgressMonitor;
76import org.greenstone.gatherer.util.Codec;
77import org.greenstone.gatherer.util.StaticStrings;
78import org.greenstone.gatherer.util.Utility;
79import org.greenstone.gatherer.util.XMLTools;
80import org.w3c.dom.*;
81
82import org.greenstone.gatherer.util.GS3ServerThread;
83
84/** This class manages many aspects of the collection, from its creation via scripts, data access via methods and its importing and building into the final collection. It is also responsible for firing appropriate event when significant changes have occured within the collection, and for creating a new metadata set manager as necessary.
85 * @author John Thompson
86 * @version 2.3
87 */
88public class CollectionManager
89 implements GShellListener, MetadataChangedListener
90{
91 /** Are we currently in the process of building? */
92 static private boolean building = false;
93 /** Are we currently in the process of importing? */
94 static private boolean importing = false;
95 /** Are we currently in the process of scheduling? */
96 static private boolean scheduling = false;
97 /** The objects listening for CollectionContentsChanged events. */
98 static private ArrayList collection_contents_changed_listeners = new ArrayList();
99 /** The collection this manager is managing! */
100 static private Collection collection = null;
101 /** The collection tree (used in both Gather and Enrich panes). */
102 static private CollectionTree collection_tree = null;
103 /** The collection tree model. */
104 static private CollectionTreeModel collection_tree_model = null;
105 /** An inner class listener responsible for noting tree changes and resetting saved when they occur. */
106 static private FMTreeModelListener fm_tree_model_listener = null;
107 /** The monitor responsible for parsing the build process. */
108 static private GShellProgressMonitor build_monitor = null;
109 /** The monitor responsible for parsing the import process. */
110 static private GShellProgressMonitor import_monitor = null;
111 /** The monitor responsible for parsing the scheduler process. */
112 static private GShellProgressMonitor schedule_monitor = null;
113 ///** The monitor responsible for parsing the fedora collection delete process. */
114 //static private GShellProgressMonitor fedora_coldelete_monitor = null;
115
116 static private String delete_collection_name = null;
117
118 /** The name of the standard lock file. */
119 static final public String LOCK_FILE = "gli.lck";
120
121 /** Used to indicate the source of the message is the file collection methods. */
122 static final public int COLLECT = 3;
123 /** Used to indicate the source of the message is the building methods. */
124 static final public int BUILDING = 5;
125 /** Used to indicate the source of the message is in the scheduling methods...? */
126 static final public int SCHEDULING = 7;
127
128 /** To store the path to the perl scripts. In the case of local Greenstone servers,
129 * this will be the local bin/script folder. */
130 static private String scriptPath = "";
131
132 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 String user_name = System.getProperty("user.name");
877 Element person_element = (Element) XMLTools.getNodeFromNamed(default_lockfile.getDocumentElement(), "User");
878 person_element.appendChild(default_lockfile.createTextNode(user_name));
879 person_element = null;
880 user_name = null;
881 String machine_name = Utility.getMachineName();
882 Element machine_element = (Element) XMLTools.getNodeFromNamed(default_lockfile.getDocumentElement(), "Machine");
883 machine_element.appendChild(default_lockfile.createTextNode(machine_name));
884 machine_element = null;
885 machine_name = null;
886 String date_time = Utility.getDateString();
887 Element date_element = (Element) XMLTools.getNodeFromNamed(default_lockfile.getDocumentElement(), "Date");
888 date_element.appendChild(default_lockfile.createTextNode(date_time));
889 date_element = null;
890 date_time = null;
891 XMLTools.writeXMLFile(lock_file, default_lockfile);
892 }
893 catch (Exception exception) {
894 DebugStream.printStackTrace(exception);
895 }
896 }
897
898
899 public boolean deleteCollection(String collection_name)
900 {
901 // First we must release the collection from the local library, if it's running
902 if (LocalLibraryServer.isRunning() == true) {
903 LocalLibraryServer.releaseCollection(collection_name);
904 }
905
906 // if we're running FLI, it's a fedora collection, and we need to call a special
907 // delete script to delete the collection and all its documents from the fedora
908 // repository and from fedora-gsearch's index.
909 if (Configuration.fedora_info.isActive()) {
910
911 // Generate the buildcol.pl command
912 ArrayList command_parts_list = new ArrayList();
913 if (!Gatherer.isGsdlRemote) {
914 command_parts_list.add(Configuration.perl_path);
915 command_parts_list.add("-S");
916 }
917
918 command_parts_list.add(scriptPath + "g2f-deletecol.pl");
919
920 command_parts_list.add("-hostname");
921 command_parts_list.add(Configuration.fedora_info.getHostname());
922
923 command_parts_list.add("-port");
924 command_parts_list.add(Configuration.fedora_info.getPort());
925
926 command_parts_list.add("-username");
927 command_parts_list.add(Configuration.fedora_info.getUsername());
928
929 command_parts_list.add("-password");
930 command_parts_list.add(Configuration.fedora_info.getPassword());
931
932 command_parts_list.add("-protocol");
933 command_parts_list.add(Configuration.fedora_info.getProtocol());
934
935 command_parts_list.add("-gli");
936 command_parts_list.add("-language");
937 command_parts_list.add(Configuration.getLanguage());
938
939 if(Gatherer.GS3) {
940 command_parts_list.add("-site");
941 command_parts_list.add(Configuration.site_name);
942 }
943
944 if(!Gatherer.isGsdlRemote) {
945 command_parts_list.add("-collectdir");
946 command_parts_list.add(getCollectDirectory()); // <../collect/>
947 }
948
949 command_parts_list.add(collection_name);
950
951 // Run the g2f-deletecol.pl to remove the fedora collection
952 String[] command_parts = (String[]) command_parts_list.toArray(new String[0]);
953 GShell shell = new GShell(command_parts, GShell.DELETE, COLLECT, this, null, GShell.GSHELL_FEDORA_COLDELETE); // fedora_coldelete_monitor set to null
954 shell.start();
955
956 delete_collection_name = collection_name;
957 return true; // we assume it succeeded for now, wait until the process returns
958 // and then proceed to delete the collection directory
959 }
960 else { // not a fedora collection
961
962 // Delete the collection on the server if we're using a remote Greenstone
963 if (Gatherer.isGsdlRemote) {
964 Gatherer.remoteGreenstoneServer.deleteCollection(collection_name);
965 }
966
967 // if Greenstone3, need to deactivate the collection on the server
968 if (Gatherer.GS3) {
969 Gatherer.configGS3Server(Configuration.site_name, ServletConfiguration.DEACTIVATE_COMMAND + collection_name);
970 }
971 // Now delete the collection directory
972 return Utility.delete(new File(getCollectionDirectoryPath(collection_name)));
973 }
974 }
975
976
977 public void fireFileAddedToCollection(File file)
978 {
979 // Send the event off to all the CollectionContentsChangedListeners
980 for (int i = 0; i < collection_contents_changed_listeners.size(); i++) {
981 ((CollectionContentsChangedListener) collection_contents_changed_listeners.get(i)).fileAddedToCollection(file);
982 }
983 }
984
985
986 /** Retrieve the current collection.
987 * @return The <strong>Collection</strong> itself.
988 */
989 public Collection getCollection() {
990 return collection;
991 }
992
993
994 /** Returns the absolute filename of the specified collection's directory.
995 */
996 static public String getCollectionDirectoryPath(String collection_name)
997 {
998 return Gatherer.getCollectDirectoryPath() + collection_name + File.separator;
999 }
1000
1001
1002 /** Returns the absolute filename of the loaded collection's archives directory.
1003 */
1004 static public String getLoadedCollectionArchivesDirectoryPath()
1005 {
1006 return getLoadedCollectionDirectoryPath() + "archives" + File.separator;
1007 }
1008
1009 /** Returns the absolute filename of the loaded collection's export directory.
1010 */
1011 static public String getLoadedCollectionExportDirectoryPath()
1012 {
1013 return getLoadedCollectionDirectoryPath() + "export" + File.separator;
1014 }
1015
1016
1017
1018 /** Returns the absolute filename of the loaded collection's building directory.
1019 */
1020 static public String getLoadedCollectionBuildingDirectoryPath()
1021 {
1022 return getLoadedCollectionDirectoryPath() + "building" + File.separator;
1023 }
1024
1025
1026 /** Returns the absolute filename of the loaded collection's collect.cfg file.
1027 */
1028 static public String getLoadedCollectionCfgFilePath()
1029 {
1030 String path = (Gatherer.GS3 == true)? Utility.COLLECTION_CONFIG_XML : Utility.COLLECT_CFG;
1031 return getLoadedCollectionEtcDirectoryPath() + path;
1032 }
1033
1034
1035 /** Returns the absolute filename of the loaded collection's directory.
1036 */
1037 static public String getLoadedCollectionDirectoryPath()
1038 {
1039 return collection.getCollectionDirectory().getPath() + File.separator;
1040 }
1041
1042
1043 /** Returns the absolute filename of the loaded collection's etc directory.
1044 */
1045 static public String getLoadedCollectionEtcDirectoryPath()
1046 {
1047 return getLoadedCollectionDirectoryPath() + "etc" + File.separator;
1048 }
1049
1050
1051 /** Returns the absolute filename of the loaded collection's .col file.
1052 */
1053 static public String getLoadedCollectionColFilePath()
1054 {
1055 return getLoadedCollectionDirectoryPath() + "gli.col";
1056 }
1057
1058
1059 /** Returns the absolute filename of the loaded collection's images directory.
1060 */
1061 static public String getLoadedCollectionImagesDirectoryPath()
1062 {
1063 return getLoadedCollectionDirectoryPath() + "images" + File.separator;
1064 }
1065
1066
1067 /** Returns the absolute filename of the loaded collection's import directory.
1068 */
1069 static public String getLoadedCollectionImportDirectoryPath()
1070 {
1071 return getLoadedCollectionDirectoryPath() + "import" + File.separator;
1072 }
1073
1074
1075 /** Returns the absolute filename of the loaded collection's index directory.
1076 */
1077 static public String getLoadedCollectionIndexDirectoryPath()
1078 {
1079 return getLoadedCollectionDirectoryPath() + "index" + File.separator;
1080 }
1081
1082
1083 /** Returns the absolute filename of the loaded collection's log directory.
1084 */
1085 static public String getLoadedCollectionLogDirectoryPath()
1086 {
1087 return getLoadedCollectionDirectoryPath() + "log" + File.separator;
1088 }
1089
1090
1091 /** Returns the absolute filename of the loaded collection's macros directory.
1092 */
1093 static public String getLoadedCollectionMacrosDirectoryPath()
1094 {
1095 return getLoadedCollectionDirectoryPath() + "macros" + File.separator;
1096 }
1097
1098
1099 /** Returns the absolute filename of the loaded collection's metadata directory.
1100 */
1101 static public String getLoadedCollectionMetadataDirectoryPath()
1102 {
1103 return getLoadedCollectionDirectoryPath() + "metadata" + File.separator;
1104 }
1105
1106
1107 /** Returns the (group-qualified) name of the loaded collection with
1108 * OS-dependent file separator.
1109 */
1110 static public String getLoadedCollectionName()
1111 {
1112 return CollectionManager.getLoadedCollectionName(false);
1113 }
1114
1115 /** Returns the (group-qualified) name of the loaded collection with
1116 * OS-dependent space separator.
1117 * @url true if url-type forward slashes, false if OS-dependent filesystem slashes.
1118 */
1119 static public String getLoadedCollectionName(boolean url)
1120 {
1121 if (collection != null) {
1122 //return collection.getName();
1123 return collection.getGroupQualifiedName(url);
1124 }
1125
1126 return null;
1127 }
1128
1129 /** @return the subname of any collection (stripped of any collection-group). */
1130 static public String getLoadedCollectionTailName()
1131 {
1132 if (collection != null) {
1133 return collection.getCollectionTailName();
1134 }
1135
1136 return null;
1137 }
1138
1139 /** Returns the "collectionGroupName/collectionName" or just the collectionName
1140 * depending on whether the collection is part of a collection group or not.
1141 * If url = true, then returns the sub-path as a URL (containing / only),
1142 * and if url = false, then the sub-path is returned in filepath form
1143 * (\ or /, depending on the OS).
1144 */
1145 static public String getLoadedGroupQualifiedCollectionName(boolean url)
1146 {
1147 if (collection != null) {
1148 return collection.getGroupQualifiedName(url);
1149 }
1150
1151 return null;
1152 }
1153
1154 public CollectionTree getCollectionTree()
1155 {
1156 if (collection_tree == null) {
1157 collection_tree = new CollectionTree(collection_tree_model, true);
1158 }
1159
1160 return collection_tree;
1161 }
1162
1163
1164 /** Retrieve the tree model associated with the current collection. */
1165 public CollectionTreeModel getCollectionTreeModel()
1166 {
1167 if (collection_tree_model == null && collection != null) {
1168 // Use the import directory to generate a new CollectionTreeModel
1169 collection_tree_model = new CollectionTreeModel(new CollectionTreeNode(new File(getLoadedCollectionImportDirectoryPath())));
1170 // Ensure that the manager is a change listener for the tree.
1171 if (fm_tree_model_listener == null) {
1172 fm_tree_model_listener = new FMTreeModelListener();
1173 }
1174 collection_tree_model.addTreeModelListener(fm_tree_model_listener);
1175 }
1176 return collection_tree_model;
1177 }
1178
1179
1180 /** This method when called, creates a new GShell in order to run the import.pl script.
1181 * @see org.greenstone.gatherer.Configuration
1182 * @see org.greenstone.gatherer.Gatherer
1183 * @see org.greenstone.gatherer.gui.BuildOptions
1184 * @see org.greenstone.gatherer.shell.GShell
1185 * @see org.greenstone.gatherer.shell.GShellListener
1186 * @see org.greenstone.gatherer.shell.GShellProgressMonitor
1187 * @see org.greenstone.gatherer.util.Utility
1188 */
1189 public void importCollection() {
1190 importing = true;
1191
1192 if (!saved()) {
1193 DebugStream.println("CollectionManager.importCollection().forcesave");
1194 import_monitor.saving();
1195 saveCollection();
1196 }
1197
1198 DebugStream.println("CollectionManager.importCollection()");
1199 DebugStream.println("Is event dispatch thread: " + SwingUtilities.isEventDispatchThread());
1200 //check that we can remove the old index before starting import
1201 File index_dir = new File(getLoadedCollectionIndexDirectoryPath());
1202 if (index_dir.exists()) {
1203 DebugStream.println("Old Index = " + index_dir.getAbsolutePath()+", testing for deletability");
1204 if (!canDelete(index_dir)) {
1205 // tell the user
1206 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Cannot_Delete_Index"), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1207 // tell the gui manager
1208 // a message for the building log
1209 GShellEvent event = new GShellEvent(this, 0, GShell.IMPORT, Dictionary.get("CollectionManager.Cannot_Delete_Index_Log"), GShell.ERROR);
1210 Gatherer.g_man.create_pane.message(event);
1211 event = new GShellEvent(this, 0, GShell.IMPORT, "", GShell.ERROR);
1212 Gatherer.g_man.create_pane.processComplete(event);
1213 importing = false;
1214 return;
1215 }
1216 }
1217
1218 // Generate the import.pl command
1219 ArrayList command_parts_list = new ArrayList();
1220 if (!Gatherer.isGsdlRemote) {
1221 command_parts_list.add(Configuration.perl_path);
1222 command_parts_list.add("-S");
1223 }
1224
1225 if (Configuration.fedora_info.isActive()) {
1226 command_parts_list.add(scriptPath + "g2f-import.pl");
1227
1228 command_parts_list.add("-hostname");
1229 command_parts_list.add(Configuration.fedora_info.getHostname());
1230
1231 command_parts_list.add("-port");
1232 command_parts_list.add(Configuration.fedora_info.getPort());
1233
1234 command_parts_list.add("-username");
1235 command_parts_list.add(Configuration.fedora_info.getUsername());
1236
1237 command_parts_list.add("-password");
1238 command_parts_list.add(Configuration.fedora_info.getPassword());
1239
1240 command_parts_list.add("-protocol");
1241 command_parts_list.add(Configuration.fedora_info.getProtocol());
1242 }
1243 else {
1244 String cmdPrefix = null;
1245 if ( CollectionDesignManager.isCompleteBuild() ) {
1246 cmdPrefix = "full-";
1247 CollectionDesignManager.setImportWasFull( true );
1248 } else {
1249 cmdPrefix = "incremental-";
1250 CollectionDesignManager.setImportWasFull( false );
1251 }
1252 command_parts_list.add(scriptPath + cmdPrefix + "import.pl"); // scriptPath already set according to local or remote case
1253 }
1254
1255 command_parts_list.add("-gli");
1256 command_parts_list.add("-language");
1257 command_parts_list.add(Configuration.getLanguage());
1258
1259 if(Gatherer.GS3) {
1260 command_parts_list.add("-site");
1261 command_parts_list.add(Configuration.site_name);
1262 }
1263
1264 if(!Gatherer.isGsdlRemote) {
1265 command_parts_list.add("-collectdir");
1266 command_parts_list.add(getCollectDirectory());
1267 }
1268
1269 String[] import_options = collection.import_options.getValues();
1270 for (int i = 0; i < import_options.length; i++) {
1271 System.err.println( "Tacking on option: " + import_options[i] );
1272 command_parts_list.add(import_options[i]);
1273 }
1274
1275 command_parts_list.add(collection.getGroupQualifiedName(false)); // (colgroup/)colname
1276
1277 // Run the import.pl command
1278 String[] command_parts = (String[]) command_parts_list.toArray(new String[0]);
1279 GShell shell = new GShell(command_parts, GShell.IMPORT, BUILDING, this, import_monitor, GShell.GSHELL_IMPORT);
1280 //shell.setEventProperty("is_incremental", Boolean.toString(is_incremental));
1281 shell.addGShellListener(Gatherer.g_man.create_pane);
1282 Gatherer.g_man.create_pane.setGShell(shell); // allow the create pane to call shell.cancel()
1283 shell.addGShellListener(Gatherer.g_man.format_pane);
1284 shell.start();
1285 DebugStream.println("CollectionManager.importCollection().return");
1286
1287 importing = false;
1288 }
1289
1290
1291 public void importMetadataSet(MetadataSet external_metadata_set)
1292 {
1293 // Copy the .mds file into the collection's "metadata" folder...
1294 File external_metadata_set_file = external_metadata_set.getMetadataSetFile();
1295
1296 // ...but not if it is the redundant "hidden.mds" file
1297 if (external_metadata_set_file.getName().equals("hidden.mds")) {
1298 return;
1299 }
1300
1301 // ...and only if it doesn't already exist
1302 File metadata_set_file = new File(getLoadedCollectionMetadataDirectoryPath(), external_metadata_set_file.getName());
1303 if (!metadata_set_file.exists()) {
1304 try {
1305 Gatherer.f_man.getQueue().copyFile(external_metadata_set_file, metadata_set_file, false);
1306
1307 // If we're using a remote Greenstone server, upload the metadata file
1308 if (Gatherer.isGsdlRemote) {
1309 Gatherer.remoteGreenstoneServer.uploadCollectionFile(collection.getGroupQualifiedName(false), metadata_set_file);
1310 }
1311 }
1312 catch (Exception exception) {
1313 DebugStream.printStackTrace(exception);
1314 }
1315
1316 // Load it into the MetadataSetManager
1317 MetadataSetManager.loadMetadataSet(metadata_set_file);
1318 }
1319 }
1320
1321 /**
1322 * In the case of a remote GS, this method takes care of reuploading a modified mds file after its
1323 * Metadata Set has been edited.
1324 * This method is mostly a copy of importMetadataSet() above, except no need to handle the hidden.mds
1325 * file as that should not even have been made available for editing in GLI.
1326 * Nor any need for MetadataSetManager.loadMetadataSet(File) as that was already done by the caller,
1327 * MetadataSetDialog.EditButtonListener.actionPerformed().
1328 */
1329 public void updateMetadataSet(MetadataSet external_metadata_set) {
1330 try {
1331 File external_metadata_set_file = external_metadata_set.getMetadataSetFile();
1332 File metadata_set_file = new File(getLoadedCollectionMetadataDirectoryPath(), external_metadata_set_file.getName());
1333
1334 // If we're using a remote Greenstone server, upload the metadata file
1335 if (Gatherer.isGsdlRemote) {
1336 Gatherer.remoteGreenstoneServer.uploadCollectionFile(collection.getGroupQualifiedName(false), metadata_set_file);
1337 }
1338 } catch (Exception exception) {
1339 DebugStream.printStackTrace(exception);
1340 }
1341 }
1342
1343
1344 /** 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.
1345 * @return true if the gli is currently importing
1346 */
1347 public boolean isImporting() {
1348 return importing;
1349 }
1350
1351
1352 public void reloadAfterConfigFileEdited() {
1353 // Copying just the part of LoadCollectionInternal below that loads the config file
1354 // Need to reload the *existing* config file, however. So calling custom method reloadConfig()
1355
1356 // Don't see why this stuff here (vs LoadCollectionInternal) would need to happen in its own
1357 // Thread for my use: when the modal Edit > collectionConfig.xml dialog has saved and closed.
1358
1359 // reload current collection's config
1360 collection.cdm.reloadConfig();
1361
1362 // We're done. Let everyone know.
1363 DebugStream.println(Dictionary.get("CollectionManager.Loading_Successful", collection.getName()));
1364 Gatherer.refresh(Gatherer.COLLECTION_OPENED);
1365 }
1366
1367 public void loadCollection(String collection_file_path)
1368 {
1369 // Display a modal progress popup to indicate that the collection is being loaded
1370 ModalProgressPopup load_collection_progress_popup = new ModalProgressPopup(Dictionary.get("CollectionManager.Loading_Collection"), Dictionary.get("CollectionManager.Loading_Collection_Please_Wait"));
1371 load_collection_progress_popup.display();
1372
1373 // Load the collection on a separate thread so the progress bar updates correctly
1374 (new LoadCollectionTask(collection_file_path, load_collection_progress_popup)).start();
1375 //SwingUtilities.invokeLater(new LoadCollectionTask(collection_file_path, load_collection_progress_popup));
1376 }
1377
1378
1379 private class LoadCollectionTask
1380 extends Thread
1381 {
1382 private String collection_file_path = null;
1383 private ModalProgressPopup load_collection_progress_popup = null;
1384
1385 public LoadCollectionTask(String collection_file_path, ModalProgressPopup load_collection_progress_popup)
1386 {
1387 this.collection_file_path = collection_file_path;
1388 this.load_collection_progress_popup = load_collection_progress_popup;
1389 }
1390
1391 public void run()
1392 {
1393 loadCollectionInternal(collection_file_path);
1394 load_collection_progress_popup.close();
1395 Gatherer.setMenuBarEnabled(true);
1396 }
1397 }
1398
1399
1400 /** Attempts to load the given collection. Currently uses simple serialization of the collection class.
1401 * @param location The path to the collection as a <strong>String</strong>.
1402 * @see org.greenstone.gatherer.Configuration
1403 * @see org.greenstone.gatherer.Gatherer
1404 * @see org.greenstone.gatherer.collection.Collection
1405 * @see org.greenstone.gatherer.util.Utility
1406 */
1407 private void loadCollectionInternal(String location)
1408 {
1409 DebugStream.println("Loading collection " + location + "...");
1410
1411
1412 // Check we have actually been given a .col file.
1413 if (!location.endsWith(".col")) {
1414 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Not_Col_File", location), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1415 DebugStream.println("CollectionManager.loadCollection: Haven't been given a .col file.");
1416 return;
1417 }
1418
1419 // Check that the collection configuration file is available
1420 File collection_file = new File(location);
1421
1422 //String collection_name = collection_directory.getName();
1423 String collection_name = "";
1424 File collection_directory = collection_file.getParentFile();
1425
1426 // To get colname = (colgroup/)coltailname, subtract Gatherer.getCollectDirectoryPath() from collection_directory:
1427 int index = collection_directory.getAbsolutePath().indexOf(Gatherer.getCollectDirectoryPath());
1428 if(index == -1) {
1429 System.err.println("*** ERROR: collection directory " + collection_directory + " is not located in collect folder: " + Gatherer.getCollectDirectoryPath());
1430 } else {
1431 index += Gatherer.getCollectDirectoryPath().length();
1432 collection_name = collection_directory.getAbsolutePath().substring(index);
1433 }
1434
1435 if (Gatherer.isGsdlRemote) {
1436 if (Gatherer.remoteGreenstoneServer.downloadCollection(collection_name).equals("")) {
1437 return;
1438 }
1439 }
1440
1441 // Ensure that the collection directory exists
1442 if (collection_directory == null || !collection_directory.exists()) {
1443 // We can't open this
1444 System.err.println("CollectionManager.loadCollection: No collection directory.");
1445 return;
1446 }
1447
1448 String file_str = (Gatherer.GS3)? Utility.CONFIG_GS3_FILE : Utility.CONFIG_FILE;
1449 File collection_config_file = new File(collection_directory, file_str);
1450 if (!collection_config_file.exists()) {
1451 System.err.println("CollectionManager.loadCollection: No config file.");
1452 collection_directory = null;
1453 collection_config_file = null;
1454 return;
1455 }
1456
1457 // Ensure that an import directory exists for this collection
1458 File collection_import_directory = new File(collection_directory, "import");
1459 if (!collection_import_directory.exists()) {
1460 collection_import_directory.mkdir();
1461 }
1462
1463 // Special case of a user trying to open an old greenstone collection.
1464 boolean non_gli_collection = false;
1465 File collection_metadata_directory = new File(collection_directory, "metadata");
1466 if (!collection_metadata_directory.exists()) {
1467 DebugStream.println("Loading non-gatherer collection...");
1468 // Show a warning message in case user wants to quit now
1469 non_gli_collection = true;
1470 WarningDialog legacy_dialog = new WarningDialog("warning.LegacyCollection", Dictionary.get("LegacyCollection.Title"), Dictionary.get("LegacyCollection.Message"), null, true);
1471 if (legacy_dialog.display()==JOptionPane.CANCEL_OPTION) {
1472 legacy_dialog.dispose();
1473 collection_directory = null;
1474 collection_config_file = null;
1475 return;
1476 }
1477 legacy_dialog.dispose();
1478
1479 }
1480
1481 // Now determine if a lock already exists on this collection.
1482 File lock_file = new File(collection_file.getParentFile(), LOCK_FILE);
1483 if (lock_file.exists()) {
1484 LockFileDialog dialog = new LockFileDialog(Gatherer.g_man, collection_name, lock_file);
1485 TestingPreparation.setNamesRecursively(dialog);
1486 int choice = dialog.getChoice();
1487 dialog.dispose();
1488 dialog = null;
1489
1490 if (choice != LockFileDialog.YES_OPTION) {
1491 // user has cancelled
1492 lock_file = null;
1493 collection_directory = null;
1494 collection_config_file = null;
1495 return;
1496 }
1497
1498 lock_file.delete();
1499 }
1500
1501 // now we are using gli.col - old colls may have used the collection name
1502 if (!collection_file.exists()) {
1503 File old_coll_file = new File(collection_directory, collection_name+".col");
1504 if (old_coll_file.exists()) {
1505 try {
1506 old_coll_file.renameTo(collection_file);
1507 } catch (Exception e) {
1508 DebugStream.println("Couldn't rename "+old_coll_file.getName()+" to gli.col. Will just carry on with default gli.col");
1509 // but just carry on.
1510 }
1511 }
1512 }
1513
1514 try {
1515 // Create a lock file.
1516 createLockFile(lock_file);
1517 // This lock file may not have been created so check
1518 if(!lock_file.canWrite()) {
1519 // The lock file cannot be written to. Most likely cause incorrect file permissions.
1520 System.err.println("Cannot write lock file!");
1521 String args[] = new String[2];
1522 args[0] = location;
1523 args[1] = Dictionary.get("FileActions.Write_Not_Permitted_Message", new String[]{lock_file.getAbsolutePath()});
1524 if(Gatherer.client_operating_system.toUpperCase().indexOf("WINDOWS")!=-1){
1525 //if(Gatherer.client_operating_system.toUpperCase().indexOf("VISTA")!=-1){
1526 args[1] += Dictionary.get("FileActions.File_Permission_Detail", new String[]{Configuration.gsdl_path, System.getProperty("user.name")});
1527 //}
1528 }
1529 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Cannot_Open_With_Reason", args), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1530 args = null;
1531 return;
1532 }
1533
1534 // need to fix this up as currently it craps out if the .col file is not there, which is may not always be.
1535 if (canDoScheduling() && collection_file.exists()) {
1536 //THIS LOOKS LIKE THE BEST PLACE TO TRY AND UPDATE .col FILES FOR EXISTING COLLECTIONS...Wendy
1537 // Don't need to update anything if collection_file doesn't exist yet.
1538 //First, see if "Schedule" exists in the XMl File...
1539 BufferedReader bir = new BufferedReader(new FileReader(collection_file));
1540 boolean flag = false;
1541 try {
1542 String stmp = new String();
1543
1544 while((stmp = bir.readLine()) != null) {
1545 stmp = stmp.trim();
1546 if(stmp.equals("<Schedule>") || stmp.equals("<Schedule/>")) {
1547 flag = true;
1548 break;
1549 }
1550 }
1551 bir.close();
1552
1553 } catch (IOException ioe) {
1554 DebugStream.printStackTrace(ioe);
1555 }
1556
1557 //modify if old .col (i.e. no Schedule exists in XML file)
1558 if(!flag) {
1559 File new_collection_file = new File(collection_directory.getAbsolutePath() + "/tmp.col");
1560
1561
1562 BufferedWriter bor = new BufferedWriter(new FileWriter(new_collection_file));
1563 bir = new BufferedReader(new FileReader(collection_file));
1564
1565 try {
1566 String stmp = new String();
1567 while((stmp = bir.readLine()) != null) {
1568 String stmp2 = stmp.trim();
1569 if(stmp2.startsWith("<!ELEMENT Argument")) {
1570 bor.write(" <!ELEMENT Schedule (Arguments*)>\n");
1571 }
1572 else if(stmp2.equals("</BuildConfig>")) {
1573 bor.write(" <Schedule/>\n");
1574 }
1575
1576 bor.write(stmp + "\n");
1577
1578 }
1579 bir.close();
1580 bor.close();
1581 } catch (IOException ioe) {
1582 DebugStream.printStackTrace(ioe);
1583 }
1584
1585 //copy over tmp.col to replace
1586 try {
1587 collection_file.delete();
1588 new_collection_file.renameTo(collection_file);
1589 } catch (Exception e) {
1590 DebugStream.printStackTrace(e);
1591 }
1592 }
1593 }
1594
1595 // Open the collection file
1596 this.collection = new Collection(collection_file);
1597 if (collection.error) {
1598 collection = null;
1599 // Remove lock file
1600 if (lock_file.exists()) {
1601 lock_file.delete();
1602 }
1603 throw(new Exception(Dictionary.get("CollectionManager.Missing_Config"))); // this error message does not agree with the error
1604 }
1605
1606 if (canDoScheduling()) {
1607 scheduling();
1608 }
1609
1610 // These may have been set in the past, but are no longer used
1611 // by GLI
1612 collection.import_options.removeValue("removeold");
1613 collection.import_options.removeValue("keepold");
1614
1615 MetadataSetManager.clearMetadataSets();
1616 MetadataSetManager.loadMetadataSets(collection_metadata_directory);
1617
1618 // Make sure we always have the extracted metadata set
1619 addRequiredMetadataSets();
1620
1621 ProfileXMLFileManager.loadProfileXMLFile(collection_metadata_directory);
1622
1623 // If this is a non-GLI (legacy) collection, load the default metadata sets
1624 if (non_gli_collection) {
1625 addDefaultMetadataSets();
1626
1627 // Recurse the import folder tree, backing up the metadata.xml files before they are edited
1628 LegacyCollectionImporter.backupMetadataXMLFiles(collection_directory);
1629 }
1630
1631 // Read through the metadata.xml files in the import directory, building up the metadata value trees
1632 MetadataXMLFileManager.clearMetadataXMLFiles();
1633 MetadataXMLFileManager.loadMetadataXMLFiles(collection_import_directory,collection.toSkimFile());
1634
1635
1636 // get rid of the previous scan through docxml files
1637 DocXMLFileManager.clearDocXMLFiles();
1638
1639 if (Configuration.fedora_info.isActive()) { // FLI case
1640 // Read through the docmets.xml files in the export directory
1641 File collection_export_directory = new File(getLoadedCollectionExportDirectoryPath());
1642 DocXMLFileManager.loadDocXMLFiles(collection_export_directory,"docmets.xml");
1643 }
1644 else {
1645 // Read through the doc.xml files in the archives directory
1646 File collection_archives_directory = new File(getLoadedCollectionArchivesDirectoryPath());
1647 DocXMLFileManager.loadDocXMLFiles(collection_archives_directory,"doc.xml");
1648 }
1649
1650
1651 // Get a list of the collection specific classifiers and plugins
1652 Classifiers.loadClassifiersList(collection_name);
1653 Plugins.loadPluginsList(collection_name);
1654
1655 collection.cdm = new CollectionDesignManager(collection_config_file);
1656 if (non_gli_collection) {
1657 // Change the classifiers to use the namespaced element names
1658 LegacyCollectionImporter.updateClassifiers(collection.cdm);
1659 }
1660
1661 // We're done. Let everyone know.
1662 DebugStream.println(Dictionary.get("CollectionManager.Loading_Successful", collection_name));
1663 Gatherer.refresh(Gatherer.COLLECTION_OPENED);
1664 }
1665 catch (Exception error) {
1666 // There is obviously no existing collection present.
1667 DebugStream.printStackTrace(error);
1668 error.printStackTrace();
1669 if(error.getMessage() != null) {
1670 String[] args = new String[2];
1671 args[0] = location;
1672 args[1] = error.getMessage();
1673 //args[1] = "The Librarian Interface does not have permission to write to... Please check file permissions.";
1674 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Cannot_Open_With_Reason", args), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1675 }
1676 else {
1677 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Cannot_Open", location), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1678 }
1679 }
1680
1681 lock_file = null;
1682 collection_directory = null;
1683 collection_config_file = null;
1684 }
1685
1686 /** At present, scheduling only works for GS2, only when GS2 is local and only when GLI runs from
1687 * within a GS2 installation. This method can be adjusted as scheduling becomes available for more
1688 * more situations. */
1689 public static boolean canDoScheduling() {
1690 // Would be nice to support more of these, rather than returning false
1691 if(Gatherer.isGsdlRemote) {
1692 return false;
1693 }
1694 if(Gatherer.GS3) {
1695 return false;
1696 }
1697 if (Configuration.fedora_info.isActive()) {
1698 return false;
1699 }
1700
1701 // GS2's etc/main.cfg is necessary for scheduling, but scheduling looks for it locally:
1702 // it assumes GLI is inside a GS2 installation
1703 File mcfg = new File(LocalGreenstone.getDirectoryPath() + File.separator + "etc" + File.separator + "main.cfg");
1704 if(!mcfg.exists()) {
1705 System.out.println("Cannot do scheduling, since there is no file: " + mcfg.getAbsolutePath()
1706 + ".\nScheduling presently depends on GLI running from inside a GS2.");
1707 return false;
1708 }
1709
1710 return true;
1711 }
1712
1713 private void makeCollection(String name, String email)
1714 {
1715 // Generate the mkcol.pl command
1716 ArrayList command_parts_list = new ArrayList();
1717 if (!Gatherer.isGsdlRemote) {
1718 command_parts_list.add(Configuration.perl_path);
1719 command_parts_list.add("-S");
1720 }
1721 command_parts_list.add(scriptPath + "mkcol.pl");
1722 if(Gatherer.GS3) {
1723 command_parts_list.add(Utility.GS3MODE_ARGUMENT); // add '-gs3mode'
1724 command_parts_list.add("-site");
1725 command_parts_list.add(Configuration.site_name);
1726 }
1727
1728 if(!Gatherer.isGsdlRemote) {
1729 command_parts_list.add("-collectdir");
1730 command_parts_list.add(getDefaultCollectDirectory());
1731 }
1732 command_parts_list.add("-win31compat");
1733 command_parts_list.add((Gatherer.isGsdlRemote) ? "false" : "true");
1734
1735 if (email != null && !email.equals("")) {
1736 command_parts_list.add("-creator");
1737 command_parts_list.add(email);
1738 }
1739
1740 command_parts_list.add(name);
1741
1742 // Run the mkcol.pl command
1743 String[] command_parts = (String[]) command_parts_list.toArray(new String[0]);
1744 //for(int i = 0; i < command_parts.length; i++) {
1745 ///ystem.err.println("\""+command_parts[i]+"\"");
1746 //}
1747
1748 GShell process = new GShell(command_parts, GShell.NEW, COLLECT, this, null, GShell.GSHELL_NEW);
1749 process.run(); // Don't bother threading this... yet
1750 }
1751
1752
1753 /** 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.
1754 * @param event A <strong>GShellEvent</strong> which contains a the message.
1755 */
1756 public synchronized void message(GShellEvent event) {
1757
1758 }
1759
1760
1761 public void metadataChanged(CollectionTreeNode[] file_nodes)
1762 {
1763 if (collection != null) {
1764 collection.setMetadataChanged(true);
1765
1766 // we're only going to refresh the tree's already visible nodes (and reselect them) IFF
1767 // gs.FilenameEncoding meta was set on any files/folders and the filenames of the
1768 // affected CollectionTreeNodes need to be recalculated
1769 if(FilenameEncoding.isRefreshRequired()) {
1770
1771 // refreshes the relevant part of the tree
1772 TreePath[] paths = collection_tree.getSelectionPaths();
1773 if(paths != null) {
1774 for(int i = 0; i < paths.length; i++) {
1775 collection_tree_model.refresh(paths[i]);
1776 collection_tree.setSelectionPath(paths[i]);
1777 }
1778 }
1779 // refreshed the tree, so turn off the requirement to refresh
1780 FilenameEncoding.setRefreshRequired(false);
1781 }
1782 }
1783 }
1784
1785
1786 public void openCollectionFromLastTime() {
1787 // If there was an open collection last session, reopen it.
1788 // (this method doesn't get called if there was no open collection or only a collect folder
1789 // instead of any previously-opened collection)
1790
1791 // Load the collection now
1792 loadCollection(Gatherer.open_collection_file_path);
1793 }
1794
1795
1796 /** This call is fired whenever a process within a GShell created by this class begins.
1797 * @param event A <strong>GShellEvent</strong> containing information about the GShell process.
1798 * @see org.greenstone.gatherer.Gatherer
1799 * @see org.greenstone.gatherer.gui.GUIManager
1800 * @see org.greenstone.gatherer.shell.GShell
1801 */
1802 public synchronized void processBegun(GShellEvent event) {
1803 DebugStream.println("CollectionManager.processBegun(" + event.getType() + ")");
1804 ///ystem.err.println("ProcessBegun " + event.getType());
1805 // If this is one of the types where we wish to lock user control
1806 Gatherer.g_man.lockCollection((event.getType() == GShell.IMPORT), true);
1807 }
1808 /** This call is fired whenever a process within a GShell created by this class ends.
1809 * @param event A <strong>GShellEvent</strong> containing information about the GShell process.
1810 * @see org.greenstone.gatherer.Gatherer
1811 * @see org.greenstone.gatherer.gui.GUIManager
1812 * @see org.greenstone.gatherer.shell.GShell
1813 */
1814 public synchronized void processComplete(GShellEvent event) {
1815 //ystem.err.println("CollectionManager.processComplete(" + event.getType() + ")");
1816 Gatherer.g_man.lockCollection((event.getType() == GShell.IMPORT), false);
1817 ///ystem.err.println("Received process complete event - " + event);
1818 // If we were running an import, now run a build.
1819 if(event.getType() == GShell.IMPORT && event.getStatus() == GShell.OK) {
1820 // Finish import.
1821 collection.setImported(true);
1822 collection.setFilesChanged(false);
1823 collection.setMetadataChanged(false);
1824 buildCollection();
1825 }
1826 else if(event.getType() == GShell.SCHEDULE && event.getStatus() == GShell.OK ) {
1827
1828 WarningDialog collection_built_warning_dialog = new WarningDialog("warning.ScheduleBuilt", Dictionary.get("ScheduleBuilt.Title"), Dictionary.get("ScheduleBuilt.Message"), null, false);
1829 collection_built_warning_dialog.setMessageOnly(true); // Not a warning
1830 collection_built_warning_dialog.display();
1831 collection_built_warning_dialog.dispose();
1832 collection_built_warning_dialog = null;
1833 }
1834 // If we were running a build, now is when we move files across.
1835 else if(event.getType() == GShell.BUILD && event.getStatus() == GShell.OK) {
1836
1837 if ( CollectionDesignManager.buildcolWasFull() ) {
1838
1839 // No installCollection() for GS3 solr collection: activate will take care of that
1840 // and no call to configGS3Server for solr collection
1841 if(CollectionManager.isSolrCollection()) {
1842
1843 DebugStream.println("Solr collection build complete: building already moved to index by activate.pl.");
1844
1845 // Finished building,
1846 // For now, for a GS3 solr collection, we'd have stopped the GS3 server before building
1847 // and will now need to restart it.
1848 /*GS3ServerThread thread = new GS3ServerThread(Configuration.gsdl3_src_path, "restart");
1849 thread.start();*/
1850
1851 // Give the GS3 server time to restart:
1852 // the GS3ServerThread above waits for the process to terminate. ant restart target calls the start-tomcat ant target
1853 // and that takes waits 5 seconds and polls to see if a GS3 server index page has loaded. So no need to sleep here
1854
1855 }
1856
1857 else if(installCollection()) {
1858 // If we have a local library running then ask it to add our newly created collection
1859 if (LocalLibraryServer.isRunning() == true) {
1860 LocalLibraryServer.addCollection(collection.getName());
1861 }
1862 else if (Gatherer.GS3) {
1863 //xiao comment out this: convertToGS3Collection();
1864 Gatherer.configGS3Server(Configuration.site_name, ServletConfiguration.ADD_COMMAND + collection.getName());
1865 }
1866
1867 // Fire a collection changed first to update the preview etc buttons
1868 Gatherer.refresh(Gatherer.COLLECTION_REBUILT);
1869
1870 // Now display a message dialog saying its all built
1871 WarningDialog collection_built_warning_dialog = new WarningDialog("warning.CollectionBuilt", Dictionary.get("CollectionBuilt.Title"), Dictionary.get("CollectionBuilt.Message"), null, false);
1872 collection_built_warning_dialog.setMessageOnly(true); // Not a warning
1873 collection_built_warning_dialog.display();
1874 collection_built_warning_dialog.dispose();
1875 collection_built_warning_dialog = null;
1876
1877 //Set nothing as needing rebuilding, as a build has just finished :-)
1878 CollectionDesignManager.resetRebuildTypeRequired();
1879 }
1880 else {
1881 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Preview_Ready_Failed"), Dictionary.get("CollectionManager.Preview_Ready_Title"), JOptionPane.ERROR_MESSAGE);
1882 Gatherer.refresh(Gatherer.COLLECTION_REBUILT);
1883 DebugStream.println("Status is ok but !installCollection()");
1884 }
1885 }
1886 }
1887
1888 else if(event.getType() == GShell.DELETE) {
1889
1890 // we can only get here if we tried to delete a fedora collection
1891
1892 if(event.getStatus() == GShell.ERROR) { // error purging the collection from fedora
1893
1894 JOptionPane.showMessageDialog(Gatherer.g_man,Dictionary.get("DeleteCollectionPrompt.Failed_Fedora_Delete", new String[]{delete_collection_name}),Dictionary.get("DeleteCollectionPrompt.Failed_Title"),JOptionPane.WARNING_MESSAGE);
1895 delete_collection_name = null; // re-zero
1896 }
1897
1898 else if(event.getStatus() == GShell.OK) { // fedora purge was successful
1899
1900 if(delete_collection_name != null) {
1901 if (Gatherer.isGsdlRemote) {
1902 Gatherer.remoteGreenstoneServer.deleteCollection(delete_collection_name);
1903 }
1904
1905 // if Greenstone3, need to deactivate the collection on the server
1906 if (Gatherer.GS3) {
1907 Gatherer.configGS3Server(Configuration.site_name, ServletConfiguration.DEACTIVATE_COMMAND + delete_collection_name);
1908 }
1909
1910 // Now at last, can delete the collection directory as for a normal collection
1911 boolean success = Utility.delete(new File(getCollectionDirectoryPath(delete_collection_name)));
1912
1913 if (!success) {
1914 JOptionPane.showMessageDialog(Gatherer.g_man,Dictionary.get("DeleteCollectionPrompt.Failed_Delete", new String[]{delete_collection_name}),Dictionary.get("DeleteCollectionPrompt.Failed_Title"),JOptionPane.WARNING_MESSAGE);
1915 }
1916 delete_collection_name = null; // re-zero
1917 }
1918
1919 }
1920 }
1921
1922 else if (event.getStatus() == GShell.CANCELLED) {
1923 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Build_Cancelled"), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1924 Gatherer.g_man.repaint();
1925 }
1926 else if (event.getStatus() == GShell.ERROR) {
1927 if (event.getType() == GShell.NEW) {
1928 String name = event.getMessage();
1929 String collectDir = getCollectionDirectoryPath(name);
1930 String errMsg = "";
1931 if (!new File(getCollectionDirectoryPath(name)).exists() || !new File(getCollectionDirectoryPath(name)).canWrite()) {
1932 String reason = Dictionary.get("FileActions.Write_Not_Permitted_Message", new String[]{collectDir});
1933 errMsg = Dictionary.get("CollectionManager.Cannot_Create_Collection_With_Reason", new String[]{reason});
1934 if(Gatherer.client_operating_system.toUpperCase().indexOf("WINDOWS") != -1){
1935 //if(Gatherer.client_operating_system.toUpperCase().indexOf("VISTA")!=-1){
1936 errMsg += Dictionary.get("FileActions.File_Permission_Detail", new String[]{Configuration.gsdl_path, System.getProperty("user.name")});
1937 //}
1938 }
1939 } else {
1940 errMsg = Dictionary.get("CollectionManager.Cannot_Create_Collection");
1941 }
1942 JOptionPane.showMessageDialog(Gatherer.g_man, errMsg, Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1943 }
1944 else if(event.getType() == GShell.SCHEDULE) {
1945 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Schedule_Failed"), Dictionary.get("CollectionManager.Schedule_Ready_Title"), JOptionPane.ERROR_MESSAGE);
1946 }
1947 else {
1948 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Preview_Ready_Failed"), Dictionary.get("CollectionManager.Preview_Ready_Title"), JOptionPane.ERROR_MESSAGE);
1949 Gatherer.refresh(Gatherer.COLLECTION_REBUILT);
1950 }
1951
1952 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.
1953 }
1954 }
1955
1956
1957 /** Determine if the manager is ready for actions apon its collection.
1958 * @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.
1959 */
1960 static public synchronized boolean ready() {
1961 if(collection != null) {
1962 return true;
1963 }
1964 else {
1965 return false;
1966 }
1967 }
1968
1969
1970 /** This method associates the collection build monitor with the build monitor created in CreatePane.
1971 * @param monitor A <strong>GShellProgressMonitor</strong> which we will use as the build monitor.
1972 */
1973 public void registerBuildMonitor(GShellProgressMonitor monitor) {
1974 build_monitor = monitor;
1975 }
1976 /** This method associates the collection import monitor with the import monitor created in CreatePane.
1977 * @param monitor A <strong>GShellProgressMonitor</strong> which we will use as the import monitor.
1978 */
1979 public void registerImportMonitor(GShellProgressMonitor monitor) {
1980 import_monitor = monitor;
1981 }
1982
1983 public void registerScheduleMonitor(GShellProgressMonitor monitor) {
1984 schedule_monitor = monitor;
1985 }
1986
1987
1988 static public void removeCollectionContentsChangedListener(CollectionContentsChangedListener listener)
1989 {
1990 collection_contents_changed_listeners.remove(listener);
1991 }
1992
1993
1994 public void removeMetadataSet(MetadataSet metadata_set)
1995 {
1996 DebugStream.println("Removing metadata set...");
1997
1998 // Delete the .mds file from the collection's "metadata" folder...
1999 File metadata_set_file = metadata_set.getMetadataSetFile();
2000
2001 // ...but not if it is the "ex.mds" file
2002 if (metadata_set_file.getName().equals("ex.mds")) {
2003 return;
2004 }
2005
2006 // ...and only if it exists
2007 if (metadata_set_file.exists()) {
2008 metadata_set_file.delete();
2009
2010 // Unload it from the MetadataSetManager
2011 MetadataSetManager.unloadMetadataSet(metadata_set);
2012
2013 // If we're using a remote Greenstone server, delete the metadata file on the server
2014 if (Gatherer.isGsdlRemote) {
2015 Gatherer.remoteGreenstoneServer.deleteCollectionFile(collection.getGroupQualifiedName(false), metadata_set_file);
2016 }
2017 }
2018 }
2019
2020
2021 /** Used to check whether all open collections have a 'saved' state.
2022 * @return A <i>boolean</i> which is <i>true</i> if the collection has been saved.
2023 * @see org.greenstone.gatherer.collection.Collection
2024 */
2025 public boolean saved() {
2026 boolean result = true;
2027 if(collection != null) {
2028 result = collection.getSaved();
2029 }
2030 return result;
2031 }
2032
2033
2034 /** Saves the currently loaded collection. */
2035 public void saveCollection()
2036 {
2037
2038 if (collection == null) return;
2039
2040 DebugStream.println("Saving collection " + collection.getName() + "...");
2041
2042 // Change cursor to hourglass
2043 Gatherer.g_man.wait(true);
2044
2045 // Create a backup of the collection file, just in case anything goes wrong
2046 File collection_file = new File(getLoadedCollectionColFilePath());
2047 if (collection_file.exists()) {
2048 File collection_file_backup = new File(collection_file.getAbsolutePath() + "~");
2049 if (!collection_file.renameTo(collection_file_backup)) {
2050 DebugStream.println("Error in CollectionManager.saveCollection(): could not create backup file.");
2051 }
2052 collection_file_backup.deleteOnExit();
2053 }
2054
2055 // Write out the collection file
2056 collection.save();
2057
2058 // Write out the collection configuration file
2059 collection.cdm.save();
2060
2061 // Change cursor back to normal
2062 Gatherer.g_man.wait(false);
2063 }
2064
2065
2066 /** 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] */
2067 // now add in greenstone metadata set too.
2068 private void addDefaultMetadataSets()
2069 {
2070 // Add dublin core which is the default metadata set. The user
2071 // can change this later
2072 File dc_file = new File(Gatherer.getGLIMetadataDirectoryPath()+"dublin.mds");
2073 if (dc_file.exists()) {
2074 importMetadataSet(new MetadataSet(dc_file));
2075 }
2076 File gs_file = new File(Gatherer.getGLIMetadataDirectoryPath()+"greenstone.mds");
2077 if (gs_file.exists()) {
2078 importMetadataSet(new MetadataSet(gs_file));
2079 }
2080 }
2081
2082
2083 private void addRequiredMetadataSets()
2084 {
2085 // Always import the extracted metadata set
2086 File extracted_metadata_set_file = new File(Gatherer.getGLIMetadataDirectoryPath() + MetadataSetManager.EXTRACTED_METADATA_NAMESPACE + StaticStrings.METADATA_SET_EXTENSION);
2087 importMetadataSet(new MetadataSet(extracted_metadata_set_file));
2088 }
2089
2090 private String getDefaultCollectDirectory() {
2091 String collect_dir = Gatherer.getCollectDirectoryPath();
2092 // Remove erroneous file windows file separator as it causes problems when running import.pl
2093 if(collect_dir.length() > 2 && collect_dir.endsWith("\\")) {
2094 collect_dir = collect_dir.substring(0, collect_dir.length() - 1);
2095 }
2096 return collect_dir;
2097 }
2098
2099 // used as arg in the perl scripts
2100 private String getCollectDirectory() {
2101 String collect_dir = Gatherer.getCollectDirectoryPath();
2102 return collect_dir.substring(0, collect_dir.length()-1); // remove trailing slash
2103
2104 // the following will stick any colgroup at the end of the collect directory, making it no longer
2105 // possible to get the real collect dir in a general manner if this were located outside greenstone
2106 //String collect_dir = collection.getCollectionDirectory().getParentFile().getPath();
2107 //return collect_dir;
2108 }
2109
2110 public static String getBuildType() {
2111 String buildType = (new CollectionMeta( CollectionDesignManager.collect_config.getBuildType() )).getValue(CollectionMeta.TEXT);
2112 return buildType;
2113 }
2114
2115 public static boolean isSolrCollection() {
2116 return (Gatherer.GS3 && CollectionManager.getBuildType().equals("solr"));
2117 }
2118
2119
2120 /** Install collection by moving its files from building to index after a successful build.
2121 * @see org.greenstone.gatherer.Gatherer
2122 * @see org.greenstone.gatherer.util.Utility
2123 */
2124 private boolean installCollection()
2125 {
2126 if (Configuration.fedora_info.isActive()) {
2127 DebugStream.println("Fedora build complete. No need to move files.");
2128 return true;
2129 }
2130
2131 DebugStream.println("Build complete. Moving files.");
2132
2133 try {
2134 // Ensure that the local library has released this collection so we can delete the index directory
2135 if (LocalLibraryServer.isRunning() == true) {
2136 LocalLibraryServer.releaseCollection(getLoadedCollectionName(true)); // URL style slash //collection.getName());
2137 }
2138 // deactivate it in tomcat so that windows will release the index files
2139 if (Gatherer.GS3 && !Gatherer.isGsdlRemote) {
2140 Gatherer.configGS3Server(Configuration.site_name, ServletConfiguration.DEACTIVATE_COMMAND + collection.getName());
2141 }
2142 /*
2143 File index_dir = new File(getLoadedCollectionIndexDirectoryPath());
2144 DebugStream.println("Index = " + index_dir.getAbsolutePath());
2145
2146 File building_dir = new File(getLoadedCollectionBuildingDirectoryPath());
2147 DebugStream.println("Building = " + building_dir.getAbsolutePath());
2148
2149 // Get the build mode from the build options
2150 String build_mode = collection.build_options.getValue("mode");
2151
2152 // Special case for build mode "all": replace index dir with building dir
2153 if (build_mode == null || build_mode.equals(Dictionary.get("CreatePane.Mode_All"))) {
2154 // Remove the old index directory
2155 if (index_dir.exists()) {
2156 Utility.delete(index_dir);
2157
2158 // Wait for a couple of seconds, just for luck
2159 wait(2000);
2160
2161 // Check the delete worked
2162 if (index_dir.exists()) {
2163 throw new Exception(Dictionary.get("CollectionManager.Index_Not_Deleted"));
2164 }
2165 }
2166
2167 if (Gatherer.isGsdlRemote) {
2168 Gatherer.remoteGreenstoneServer.deleteCollectionFile(
2169 collection.getGroupQualifiedName(false), new File(getLoadedCollectionIndexDirectoryPath()));
2170 Gatherer.remoteGreenstoneServer.moveCollectionFile(collection.getGroupQualifiedName(false),
2171 new File(getLoadedCollectionBuildingDirectoryPath()), new File(getLoadedCollectionIndexDirectoryPath()));
2172 }
2173
2174 // Move the building directory to become the new index directory
2175 if (building_dir.renameTo(index_dir) == false) {
2176 throw new Exception(Dictionary.get("CollectionManager.Build_Not_Moved"));
2177 }
2178 }
2179
2180 // Otherwise copy everything in the building dir into the index dir
2181 else {
2182 moveContentsInto(building_dir, index_dir);
2183 }
2184
2185 // move oai tmpdb to oai livedb
2186 */
2187
2188 }
2189 catch (Exception exception) {
2190 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Install_Exception", exception.getMessage()), "Error", JOptionPane.ERROR_MESSAGE);
2191 return false;
2192 }
2193 return true;
2194 }
2195
2196
2197 /** Moves all the files in one directory into another, overwriting existing files */
2198 private void moveContentsInto(File source_directory, File target_directory)
2199 {
2200 File[] source_files = source_directory.listFiles();
2201 for (int i = 0; i < source_files.length; i++) {
2202 File source_file = source_files[i];
2203 File target_file = new File(target_directory, source_file.getName());
2204
2205 if (source_file.isDirectory()) {
2206 moveContentsInto(source_file, target_file);
2207 source_file.delete();
2208 }
2209 else {
2210 if (target_file.exists()) {
2211 target_file.delete();
2212 }
2213
2214 source_file.renameTo(target_file);
2215 }
2216 }
2217 }
2218
2219 private void updateCollectionConfigXML(File base_cfg, File new_cfg) {
2220 //In this method, the files base_cfg and new_cfg are all xml files.
2221
2222 Document base_cfg_doc = XMLTools.parseXMLFile(base_cfg);
2223 XMLTools.writeXMLFile(new_cfg, base_cfg_doc);
2224 Document new_cfg_doc = XMLTools.parseXMLFile(new_cfg);
2225 Element collection_config = new_cfg_doc.getDocumentElement();
2226
2227 Node browseNode = XMLTools.getChildByTagNameIndexed(collection_config, StaticStrings.BROWSE_STR, 0);
2228 NodeList classifier_children = ((Element)browseNode).getElementsByTagName(StaticStrings.CLASSIFIER_STR);
2229 int num_nodes = classifier_children.getLength();
2230
2231 if (num_nodes < 1) {
2232 return;
2233 }
2234
2235 // Read in the classifier command watching for hfile, metadata and sort arguments.
2236 String buttonname = null;
2237 String hfile = null;
2238 String metadata = null;
2239 String sort = null;
2240
2241 for (int i=0; i<num_nodes; i++) {
2242 Element classifier_element = (Element)classifier_children.item(i);
2243 NodeList option_children = classifier_element.getElementsByTagName(StaticStrings.OPTION_STR);
2244 for (int j=0; j<option_children.getLength(); j++) {
2245 Element option_element = (Element)option_children.item(j);
2246 String name_str = option_element.getAttribute(StaticStrings.NAME_ATTRIBUTE);
2247 String value_str = option_element.getAttribute(StaticStrings.VALUE_ATTRIBUTE);
2248
2249 if (name_str == null || name_str.equals("")) {
2250 continue;
2251 }
2252 if (name_str != null && value_str == null ) {
2253 value_str = "";
2254 }
2255 if (name_str.equals("hfile")) {
2256 hfile = value_str;
2257 }
2258 else if (name_str.equals("metadata") && value_str != null) {
2259 String replacement = ProfileXMLFileManager.getMetadataElementFor(value_str);
2260 if (replacement != null && !replacement.equals("")) {
2261 metadata = replacement;
2262 }
2263 }
2264 else if (name_str.equals("sort") && value_str != null) {
2265 String replacement = ProfileXMLFileManager.getMetadataElementFor(value_str);
2266 if (replacement != null && !replacement.equals("")) {
2267 sort = replacement;
2268 }
2269 }
2270 else if(name_str.equals("buttonname") && value_str != null) {
2271 buttonname = value_str;
2272 }
2273 }
2274 }
2275 for (int i=0; i<num_nodes; i++) {
2276 Element classifier_element = (Element)classifier_children.item(i);
2277 NodeList option_children = classifier_element.getElementsByTagName(StaticStrings.OPTION_STR);
2278 for (int j=0; j<option_children.getLength(); j++) {
2279 Element option_element = (Element)option_children.item(j);
2280 String name_str = option_element.getAttribute(StaticStrings.NAME_ATTRIBUTE);
2281
2282 if (name_str.equals("metadata") && metadata != null) {
2283 option_element.setAttribute(StaticStrings.VALUE_ATTRIBUTE, metadata);
2284 }
2285 else if (name_str.equals("hfile") && hfile != null) {
2286 option_element.setAttribute(StaticStrings.VALUE_ATTRIBUTE, metadata + ".txt");
2287 }
2288 else if (name_str.equals("sort") && sort != null) {
2289 option_element.setAttribute(StaticStrings.VALUE_ATTRIBUTE, sort);
2290 }
2291 else if(name_str.equals("buttonname") && (buttonname == "" || buttonname == null)) {
2292 // No buttonname has been specified. Lets create one using the metadata as its value
2293 Element option = new_cfg_doc.createElement(StaticStrings.OPTION_STR);
2294 option.setAttribute(StaticStrings.NAME_ATTRIBUTE, "buttonname");
2295 option_element.setAttribute(StaticStrings.VALUE_ATTRIBUTE, metadata);
2296 classifier_element.appendChild(option);
2297 }
2298 }
2299 }
2300 }
2301
2302 private void updateCollectionCFG(File base_cfg, File new_cfg, String description, String email, String title)
2303 {
2304 boolean first_name = true;
2305 boolean first_extra = true;
2306
2307 // 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.
2308 try {
2309 BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(base_cfg), "UTF-8"));
2310 BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(new_cfg), "UTF-8"));
2311 String command = null;
2312 while((command = in.readLine()) != null) {
2313 if (command.length()==0) {
2314 // output a new line
2315 out.newLine();
2316 continue;
2317 }
2318 // We have to test the end of command for the special character '\'. If found, remove it and append the next line, then repeat.
2319 while(command.trim().endsWith("\\")) {
2320 command = command.substring(0, command.lastIndexOf("\\"));
2321 String next_line = in.readLine();
2322 if(next_line != null) {
2323 command = command + next_line;
2324 }
2325 }
2326 // commands can extend over more than one line so use the CommandTokenizer which takes care of that
2327 CommandTokenizer tokenizer = new CommandTokenizer(command, in, false);
2328 String command_type_str = tokenizer.nextToken().toLowerCase();
2329
2330 if (command_type_str.equals(StaticStrings.COLLECTIONMETADATA_STR)) {
2331 // read the whole thing in, but for collectionname, collectionextra, iconcollection, iconcollectionsmall we will ignore them
2332 StringBuffer new_command = new StringBuffer(command_type_str);
2333 String meta_name = tokenizer.nextToken();
2334 new_command.append(' ');
2335 new_command.append(meta_name);
2336 while (tokenizer.hasMoreTokens()) {
2337 new_command.append(' ');
2338 new_command.append(tokenizer.nextToken());
2339 }
2340 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)) {
2341 // dont save
2342 } else {
2343 write(out, new_command.toString());
2344 }
2345 new_command = null;
2346 continue;
2347 } // if collectionmeta
2348
2349 if (command_type_str.equals("classify")) {
2350 StringBuffer text = new StringBuffer(command_type_str);
2351 // Read in the classifier command watching for hfile, metadata and sort arguments.
2352 String buttonname = null;
2353 String hfile = null;
2354 String new_metadata = null;
2355 String old_metadata = null;
2356
2357 while(tokenizer.hasMoreTokens()) {
2358 String token = tokenizer.nextToken();
2359 if (token.equals("-hfile")) {
2360 if(tokenizer.hasMoreTokens()) {
2361 text.append(" ");
2362 text.append(token);
2363 token = tokenizer.nextToken();
2364 hfile = token;
2365 }
2366 }
2367 else if (token.equals("-metadata")) {
2368 if(tokenizer.hasMoreTokens()) {
2369 text.append(" ");
2370 text.append(token);
2371 String temp_metadata = tokenizer.nextToken();
2372 String replacement = ProfileXMLFileManager.getMetadataElementFor(temp_metadata);
2373 if (replacement != null && !replacement.equals("")) {
2374 token = replacement;
2375 old_metadata = temp_metadata;
2376 new_metadata = replacement;
2377 }
2378 else {
2379 token = temp_metadata;
2380 }
2381 temp_metadata = null;
2382 replacement = null;
2383 }
2384 }
2385 else if (token.equals("-sort")) {
2386 if(tokenizer.hasMoreTokens()) {
2387 text.append(" ");
2388 text.append(token);
2389 String temp_metadata = tokenizer.nextToken();
2390 String replacement = ProfileXMLFileManager.getMetadataElementFor(temp_metadata);
2391 if (replacement != null && !replacement.equals("")) {
2392 token = replacement;
2393 }
2394 else {
2395 token = temp_metadata;
2396 }
2397 temp_metadata = null;
2398 replacement = null;
2399 }
2400 }
2401 else if(token.equals("-buttonname")) {
2402 buttonname = token;
2403 }
2404 text.append(' ');
2405 text.append(token);
2406 token = null;
2407 }
2408
2409 // 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)!
2410 if(old_metadata != null && new_metadata != null && buttonname == null) {
2411 text.append(' ');
2412 text.append("-buttonname");
2413 text.append(' ');
2414 text.append(old_metadata);
2415 }
2416 command = text.toString();
2417 // Replace the hfile if we found it
2418 if(hfile != null && new_metadata != null) {
2419 command = command.replaceAll(hfile, new_metadata + ".txt");
2420 }
2421
2422 buttonname = null;
2423 hfile = null;
2424 new_metadata = null;
2425 old_metadata = null;
2426 write(out, command);
2427 } else {
2428 // the rest of the commands just want a string - we read in all the tokens from the tokeniser and get rid of it.
2429 StringBuffer new_command = new StringBuffer(command_type_str);
2430 while (tokenizer.hasMoreTokens()) {
2431 new_command.append(' ');
2432 new_command.append(tokenizer.nextToken());
2433 }
2434
2435 command = new_command.toString();
2436
2437 // 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.
2438 // we really want to build up the whole command here
2439 boolean format_command = command_type_str.equals("format");
2440 HashMap metadata_mapping = ProfileXMLFileManager.getMetadataMapping();
2441 if (metadata_mapping != null) {
2442 Iterator keys = metadata_mapping.keySet().iterator();
2443 while (keys.hasNext()) {
2444 String target = (String) keys.next();
2445 String replacement = (String) metadata_mapping.get(target);
2446 if (replacement != null && !replacement.equals("")) {
2447 if (format_command) {
2448 target = "\\[" + target + "\\]";
2449 replacement = "{Or}{[" + replacement + "]," + target + "}";
2450 }
2451 command = command.replaceAll(target, replacement);
2452 }
2453 }
2454 }
2455
2456 write(out, command);
2457 }
2458 tokenizer = null;
2459 }
2460 in.close();
2461 in = null;
2462 out.flush();
2463 out.close();
2464 out = null;
2465 }
2466 catch(Exception error) {
2467 DebugStream.printStackTrace(error);
2468 }
2469 // All done, I hope.
2470 }
2471
2472 private void write(BufferedWriter out, String message)
2473 throws Exception {
2474 out.write(message, 0, message.length());
2475 out.newLine();
2476 }
2477
2478
2479 /** The CollectionManager class is getting too confusing by half so I'll implement this TreeModelListener in a private class to make responsibility clear. */
2480 private class FMTreeModelListener
2481 implements TreeModelListener {
2482 /** 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.
2483 * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
2484 */
2485 public void treeNodesChanged(TreeModelEvent event) {
2486 if(collection != null) {
2487 collection.setSaved(false);
2488 collection.setFilesChanged(true);
2489 }
2490 }
2491 /** 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.
2492 * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
2493 */
2494 public void treeNodesInserted(TreeModelEvent event) {
2495 if(collection != null) {
2496 collection.setSaved(false);
2497 collection.setFilesChanged(true);
2498 }
2499 }
2500 /** 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.
2501 * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
2502 */
2503 public void treeNodesRemoved(TreeModelEvent event) {
2504 if(collection != null) {
2505 collection.setSaved(false);
2506 collection.setFilesChanged(true);
2507
2508 }
2509 }
2510 /** 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.
2511 * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
2512 */
2513 public void treeStructureChanged(TreeModelEvent event) {
2514 if(collection != null) {
2515 collection.setSaved(false);
2516 }
2517 }
2518 }
2519}
Note: See TracBrowser for help on using the repository browser.