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

Last change on this file since 29222 was 29222, checked in by ak19, 10 years ago

SOLR related. TEMPORARY changes for the GS3 workshop. Owing to the change to Solr 4.7.2, solr collections can't re-build despite activate if the GS3 server is running because there is a conflict with the jetty server launched by buildcol and jetty finds a lock on the index. The result is that one can't search the solr index after such a rebuild. Dr Bainbridge suggested a temporary measure: instead of commandline building solr collections, we will now build them in GLI. GLI will build solr collections with activate on but, for solr collections alone, it will stop the GS3 server before a build and start it again upon completion. In future, we will get rid of the solr jetty server and just have solr running over HTTP from tomcat. The Java GS3 runtime code will have to access Solr as a HTTPSolrServer rather than as an EmbeddedSolrServer at that point.

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