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

Last change on this file since 29711 was 29711, checked in by ak19, 9 years ago

Moving from using the solr jetty server to solr using the GS3 tomcat server. Now localhost:8383/solr hosts the solr server RESTful pages. Changes: 1. Minor changes to GS3 build.xml. 2. GLI no longer does the temporary stopping of the GS3 server, launching jetty server for building a solr collection, stopping jetty, restarting GS3 tomcat server. GLI leaves the GS3 server running. 3. The main changes are to ext/solr. The ext/solr/gs3-setup.sh sets the new SOLR_PORT and SOLR_HOST variables read from the GS3 build.properties, as the jetty port and host variables are no longer used. ext/solr/build.xml now puts the solr war file into tomcat's webapps, as well as helper libraries necessary (xalan related); a solr.xml context file is created from a template file and placed into tomcat's conf/Catalina/localhost; additional solr jar files are copied into tomcat/lib, as well as the slf4j bridge being copied into GS3/web/WEB-INF/lib; the solr perl code has been changed to use the new RESTful URLs and particularly to work with solr running off the GS3 tomcat server, or stop and start it as required, rather than working with (or stopping and starting) the solr jetty server. A new run_solr_server.pl executable script runs the tomcat server rather than the jetty server; major changes to the Java Solr code to no longer work with the EmbeddedSolrServer (which caused a conflict when the index is accessed by solr jetty server upon rebuild of solr collections), our solr Java code now uses HttpSolrServer to contact the solr servlet running off tomcat. 5. Still a bug: when search results go over a page after rebuilding a solr collection in GLI against a running GS3 server, the 2nd page of search results aren't present and things break. But if the server is not running, solr collections rebuild fine, so the changes do everything that GS3.06 did and more.

  • Property svn:keywords set to Author Date Id Revision
File size: 95.0 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 // Give the GS3 server time to restart:
1759 // the GS3ServerThread above waits for the process to terminate. ant restart target calls the start-tomcat ant target
1760 // and that takes waits 5 seconds and polls to see if a GS3 server index page has loaded. So no need to sleep here
1761
1762 }
1763
1764 else if(installCollection()) {
1765 // If we have a local library running then ask it to add our newly create collection
1766 if (LocalLibraryServer.isRunning() == true) {
1767 LocalLibraryServer.addCollection(collection.getName());
1768 }
1769 else if (Gatherer.GS3) {
1770 //xiao comment out this: convertToGS3Collection();
1771 Gatherer.configGS3Server(Configuration.site_name, ServletConfiguration.ADD_COMMAND + collection.getName());
1772 }
1773
1774 // Fire a collection changed first to update the preview etc buttons
1775 Gatherer.refresh(Gatherer.COLLECTION_REBUILT);
1776
1777 // Now display a message dialog saying its all built
1778 WarningDialog collection_built_warning_dialog = new WarningDialog("warning.CollectionBuilt", Dictionary.get("CollectionBuilt.Title"), Dictionary.get("CollectionBuilt.Message"), null, false);
1779 collection_built_warning_dialog.setMessageOnly(true); // Not a warning
1780 collection_built_warning_dialog.display();
1781 collection_built_warning_dialog.dispose();
1782 collection_built_warning_dialog = null;
1783
1784 //Set nothing as needing rebuilding, as a build has just finished :-)
1785 CollectionDesignManager.resetRebuildTypeRequired();
1786 }
1787 else {
1788 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Preview_Ready_Failed"), Dictionary.get("CollectionManager.Preview_Ready_Title"), JOptionPane.ERROR_MESSAGE);
1789 Gatherer.refresh(Gatherer.COLLECTION_REBUILT);
1790 DebugStream.println("Status is ok but !installCollection()");
1791 }
1792 }
1793 }
1794
1795 else if(event.getType() == GShell.DELETE) {
1796
1797 // we can only get here if we tried to delete a fedora collection
1798
1799 if(event.getStatus() == GShell.ERROR) { // error purging the collection from fedora
1800
1801 JOptionPane.showMessageDialog(Gatherer.g_man,Dictionary.get("DeleteCollectionPrompt.Failed_Fedora_Delete", new String[]{delete_collection_name}),Dictionary.get("DeleteCollectionPrompt.Failed_Title"),JOptionPane.WARNING_MESSAGE);
1802 delete_collection_name = null; // re-zero
1803 }
1804
1805 else if(event.getStatus() == GShell.OK) { // fedora purge was successful
1806
1807 if(delete_collection_name != null) {
1808 if (Gatherer.isGsdlRemote) {
1809 Gatherer.remoteGreenstoneServer.deleteCollection(delete_collection_name);
1810 }
1811
1812 // if Greenstone3, need to deactivate the collection on the server
1813 if (Gatherer.GS3) {
1814 Gatherer.configGS3Server(Configuration.site_name, ServletConfiguration.DEACTIVATE_COMMAND + delete_collection_name);
1815 }
1816
1817 // Now at last, can delete the collection directory as for a normal collection
1818 boolean success = Utility.delete(new File(getCollectionDirectoryPath(delete_collection_name)));
1819
1820 if (!success) {
1821 JOptionPane.showMessageDialog(Gatherer.g_man,Dictionary.get("DeleteCollectionPrompt.Failed_Delete", new String[]{delete_collection_name}),Dictionary.get("DeleteCollectionPrompt.Failed_Title"),JOptionPane.WARNING_MESSAGE);
1822 }
1823 delete_collection_name = null; // re-zero
1824 }
1825
1826 }
1827 }
1828
1829 else if (event.getStatus() == GShell.CANCELLED) {
1830 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Build_Cancelled"), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1831 Gatherer.g_man.repaint();
1832 }
1833 else if (event.getStatus() == GShell.ERROR) {
1834 if (event.getType() == GShell.NEW) {
1835 String name = event.getMessage();
1836 String collectDir = getCollectionDirectoryPath(name);
1837 String errMsg = "";
1838 if (!new File(getCollectionDirectoryPath(name)).exists() || !new File(getCollectionDirectoryPath(name)).canWrite()) {
1839 String reason = Dictionary.get("FileActions.Write_Not_Permitted_Message", new String[]{collectDir});
1840 errMsg = Dictionary.get("CollectionManager.Cannot_Create_Collection_With_Reason", new String[]{reason});
1841 if(Gatherer.client_operating_system.toUpperCase().indexOf("WINDOWS") != -1){
1842 //if(Gatherer.client_operating_system.toUpperCase().indexOf("VISTA")!=-1){
1843 errMsg += Dictionary.get("FileActions.File_Permission_Detail", new String[]{Configuration.gsdl_path, System.getProperty("user.name")});
1844 //}
1845 }
1846 } else {
1847 errMsg = Dictionary.get("CollectionManager.Cannot_Create_Collection");
1848 }
1849 JOptionPane.showMessageDialog(Gatherer.g_man, errMsg, Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1850 }
1851 else if(event.getType() == GShell.SCHEDULE) {
1852 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Schedule_Failed"), Dictionary.get("CollectionManager.Schedule_Ready_Title"), JOptionPane.ERROR_MESSAGE);
1853 }
1854 else {
1855 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Preview_Ready_Failed"), Dictionary.get("CollectionManager.Preview_Ready_Title"), JOptionPane.ERROR_MESSAGE);
1856 Gatherer.refresh(Gatherer.COLLECTION_REBUILT);
1857 }
1858
1859 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.
1860 }
1861 }
1862
1863
1864 /** Determine if the manager is ready for actions apon its collection.
1865 * @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.
1866 */
1867 static public synchronized boolean ready() {
1868 if(collection != null) {
1869 return true;
1870 }
1871 else {
1872 return false;
1873 }
1874 }
1875
1876
1877 /** This method associates the collection build monitor with the build monitor created in CreatePane.
1878 * @param monitor A <strong>GShellProgressMonitor</strong> which we will use as the build monitor.
1879 */
1880 public void registerBuildMonitor(GShellProgressMonitor monitor) {
1881 build_monitor = monitor;
1882 }
1883 /** This method associates the collection import monitor with the import monitor created in CreatePane.
1884 * @param monitor A <strong>GShellProgressMonitor</strong> which we will use as the import monitor.
1885 */
1886 public void registerImportMonitor(GShellProgressMonitor monitor) {
1887 import_monitor = monitor;
1888 }
1889
1890 public void registerScheduleMonitor(GShellProgressMonitor monitor) {
1891 schedule_monitor = monitor;
1892 }
1893
1894
1895 static public void removeCollectionContentsChangedListener(CollectionContentsChangedListener listener)
1896 {
1897 collection_contents_changed_listeners.remove(listener);
1898 }
1899
1900
1901 public void removeMetadataSet(MetadataSet metadata_set)
1902 {
1903 DebugStream.println("Removing metadata set...");
1904
1905 // Delete the .mds file from the collection's "metadata" folder...
1906 File metadata_set_file = metadata_set.getMetadataSetFile();
1907
1908 // ...but not if it is the "ex.mds" file
1909 if (metadata_set_file.getName().equals("ex.mds")) {
1910 return;
1911 }
1912
1913 // ...and only if it exists
1914 if (metadata_set_file.exists()) {
1915 metadata_set_file.delete();
1916
1917 // Unload it from the MetadataSetManager
1918 MetadataSetManager.unloadMetadataSet(metadata_set);
1919
1920 // If we're using a remote Greenstone server, delete the metadata file on the server
1921 if (Gatherer.isGsdlRemote) {
1922 Gatherer.remoteGreenstoneServer.deleteCollectionFile(collection.getGroupQualifiedName(false), metadata_set_file);
1923 }
1924 }
1925 }
1926
1927
1928 /** Used to check whether all open collections have a 'saved' state.
1929 * @return A <i>boolean</i> which is <i>true</i> if the collection has been saved.
1930 * @see org.greenstone.gatherer.collection.Collection
1931 */
1932 public boolean saved() {
1933 boolean result = true;
1934 if(collection != null) {
1935 result = collection.getSaved();
1936 }
1937 return result;
1938 }
1939
1940
1941 /** Saves the currently loaded collection. */
1942 public void saveCollection()
1943 {
1944
1945 if (collection == null) return;
1946
1947 DebugStream.println("Saving collection " + collection.getName() + "...");
1948
1949 // Change cursor to hourglass
1950 Gatherer.g_man.wait(true);
1951
1952 // Create a backup of the collection file, just in case anything goes wrong
1953 File collection_file = new File(getLoadedCollectionColFilePath());
1954 if (collection_file.exists()) {
1955 File collection_file_backup = new File(collection_file.getAbsolutePath() + "~");
1956 if (!collection_file.renameTo(collection_file_backup)) {
1957 DebugStream.println("Error in CollectionManager.saveCollection(): could not create backup file.");
1958 }
1959 collection_file_backup.deleteOnExit();
1960 }
1961
1962 // Write out the collection file
1963 collection.save();
1964
1965 // Write out the collection configuration file
1966 collection.cdm.save();
1967
1968 // Change cursor back to normal
1969 Gatherer.g_man.wait(false);
1970 }
1971
1972
1973 /** 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] */
1974 // now add in greenstone metadata set too.
1975 private void addDefaultMetadataSets()
1976 {
1977 // Add dublin core which is the default metadata set. The user
1978 // can change this later
1979 File dc_file = new File(Gatherer.getGLIMetadataDirectoryPath()+"dublin.mds");
1980 if (dc_file.exists()) {
1981 importMetadataSet(new MetadataSet(dc_file));
1982 }
1983 File gs_file = new File(Gatherer.getGLIMetadataDirectoryPath()+"greenstone.mds");
1984 if (gs_file.exists()) {
1985 importMetadataSet(new MetadataSet(gs_file));
1986 }
1987 }
1988
1989
1990 private void addRequiredMetadataSets()
1991 {
1992 // Always import the extracted metadata set
1993 File extracted_metadata_set_file = new File(Gatherer.getGLIMetadataDirectoryPath() + MetadataSetManager.EXTRACTED_METADATA_NAMESPACE + StaticStrings.METADATA_SET_EXTENSION);
1994 importMetadataSet(new MetadataSet(extracted_metadata_set_file));
1995 }
1996
1997 private String getDefaultCollectDirectory() {
1998 String collect_dir = Gatherer.getCollectDirectoryPath();
1999 // Remove erroneous file windows file separator as it causes problems when running import.pl
2000 if(collect_dir.length() > 2 && collect_dir.endsWith("\\")) {
2001 collect_dir = collect_dir.substring(0, collect_dir.length() - 1);
2002 }
2003 return collect_dir;
2004 }
2005
2006 // used as arg in the perl scripts
2007 private String getCollectDirectory() {
2008 String collect_dir = Gatherer.getCollectDirectoryPath();
2009 return collect_dir.substring(0, collect_dir.length()-1); // remove trailing slash
2010
2011 // the following will stick any colgroup at the end of the collect directory, making it no longer
2012 // possible to get the real collect dir in a general manner if this were located outside greenstone
2013 //String collect_dir = collection.getCollectionDirectory().getParentFile().getPath();
2014 //return collect_dir;
2015 }
2016
2017 public static String getBuildType() {
2018 String buildType = (new CollectionMeta( CollectionDesignManager.collect_config.getBuildType() )).getValue(CollectionMeta.TEXT);
2019 return buildType;
2020 }
2021
2022 public static boolean isSolrCollection() {
2023 return (Gatherer.GS3 && CollectionManager.getBuildType().equals("solr"));
2024 }
2025
2026
2027 /** Install collection by moving its files from building to index after a successful build.
2028 * @see org.greenstone.gatherer.Gatherer
2029 * @see org.greenstone.gatherer.util.Utility
2030 */
2031 private boolean installCollection()
2032 {
2033 if (Configuration.fedora_info.isActive()) {
2034 DebugStream.println("Fedora build complete. No need to move files.");
2035 return true;
2036 }
2037
2038 DebugStream.println("Build complete. Moving files.");
2039
2040 try {
2041 // Ensure that the local library has released this collection so we can delete the index directory
2042 if (LocalLibraryServer.isRunning() == true) {
2043 LocalLibraryServer.releaseCollection(getLoadedCollectionName(true)); // URL style slash //collection.getName());
2044 }
2045 // deactivate it in tomcat so that windows will release the index files
2046 if (Gatherer.GS3 && !Gatherer.isGsdlRemote) {
2047 Gatherer.configGS3Server(Configuration.site_name, ServletConfiguration.DEACTIVATE_COMMAND + collection.getName());
2048 }
2049 File index_dir = new File(getLoadedCollectionIndexDirectoryPath());
2050 DebugStream.println("Index = " + index_dir.getAbsolutePath());
2051
2052 File building_dir = new File(getLoadedCollectionBuildingDirectoryPath());
2053 DebugStream.println("Building = " + building_dir.getAbsolutePath());
2054
2055 // Get the build mode from the build options
2056 String build_mode = collection.build_options.getValue("mode");
2057
2058 // Special case for build mode "all": replace index dir with building dir
2059 if (build_mode == null || build_mode.equals(Dictionary.get("CreatePane.Mode_All"))) {
2060 // Remove the old index directory
2061 if (index_dir.exists()) {
2062 Utility.delete(index_dir);
2063
2064 // Wait for a couple of seconds, just for luck
2065 wait(2000);
2066
2067 // Check the delete worked
2068 if (index_dir.exists()) {
2069 throw new Exception(Dictionary.get("CollectionManager.Index_Not_Deleted"));
2070 }
2071 }
2072
2073 if (Gatherer.isGsdlRemote) {
2074 Gatherer.remoteGreenstoneServer.deleteCollectionFile(
2075 collection.getGroupQualifiedName(false), new File(getLoadedCollectionIndexDirectoryPath()));
2076 Gatherer.remoteGreenstoneServer.moveCollectionFile(collection.getGroupQualifiedName(false),
2077 new File(getLoadedCollectionBuildingDirectoryPath()), new File(getLoadedCollectionIndexDirectoryPath()));
2078 }
2079
2080 // Move the building directory to become the new index directory
2081 if (building_dir.renameTo(index_dir) == false) {
2082 throw new Exception(Dictionary.get("CollectionManager.Build_Not_Moved"));
2083 }
2084 }
2085
2086 // Otherwise copy everything in the building dir into the index dir
2087 else {
2088 moveContentsInto(building_dir, index_dir);
2089 }
2090 }
2091 catch (Exception exception) {
2092 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Install_Exception", exception.getMessage()), "Error", JOptionPane.ERROR_MESSAGE);
2093 return false;
2094 }
2095 return true;
2096 }
2097
2098
2099 /** Moves all the files in one directory into another, overwriting existing files */
2100 private void moveContentsInto(File source_directory, File target_directory)
2101 {
2102 File[] source_files = source_directory.listFiles();
2103 for (int i = 0; i < source_files.length; i++) {
2104 File source_file = source_files[i];
2105 File target_file = new File(target_directory, source_file.getName());
2106
2107 if (source_file.isDirectory()) {
2108 moveContentsInto(source_file, target_file);
2109 source_file.delete();
2110 }
2111 else {
2112 if (target_file.exists()) {
2113 target_file.delete();
2114 }
2115
2116 source_file.renameTo(target_file);
2117 }
2118 }
2119 }
2120
2121 private void updateCollectionConfigXML(File base_cfg, File new_cfg) {
2122 //In this method, the files base_cfg and new_cfg are all xml files.
2123
2124 Document base_cfg_doc = XMLTools.parseXMLFile(base_cfg);
2125 XMLTools.writeXMLFile(new_cfg, base_cfg_doc);
2126 Document new_cfg_doc = XMLTools.parseXMLFile(new_cfg);
2127 Element collection_config = new_cfg_doc.getDocumentElement();
2128
2129 Node browseNode = XMLTools.getChildByTagNameIndexed(collection_config, StaticStrings.BROWSE_STR, 0);
2130 NodeList classifier_children = ((Element)browseNode).getElementsByTagName(StaticStrings.CLASSIFIER_STR);
2131 int num_nodes = classifier_children.getLength();
2132
2133 if (num_nodes < 1) {
2134 return;
2135 }
2136
2137 // Read in the classifier command watching for hfile, metadata and sort arguments.
2138 String buttonname = null;
2139 String hfile = null;
2140 String metadata = null;
2141 String sort = null;
2142
2143 for (int i=0; i<num_nodes; i++) {
2144 Element classifier_element = (Element)classifier_children.item(i);
2145 NodeList option_children = classifier_element.getElementsByTagName(StaticStrings.OPTION_STR);
2146 for (int j=0; j<option_children.getLength(); j++) {
2147 Element option_element = (Element)option_children.item(j);
2148 String name_str = option_element.getAttribute(StaticStrings.NAME_ATTRIBUTE);
2149 String value_str = option_element.getAttribute(StaticStrings.VALUE_ATTRIBUTE);
2150
2151 if (name_str == null || name_str.equals("")) {
2152 continue;
2153 }
2154 if (name_str != null && value_str == null ) {
2155 value_str = "";
2156 }
2157 if (name_str.equals("hfile")) {
2158 hfile = value_str;
2159 }
2160 else if (name_str.equals("metadata") && value_str != null) {
2161 String replacement = ProfileXMLFileManager.getMetadataElementFor(value_str);
2162 if (replacement != null && !replacement.equals("")) {
2163 metadata = replacement;
2164 }
2165 }
2166 else if (name_str.equals("sort") && value_str != null) {
2167 String replacement = ProfileXMLFileManager.getMetadataElementFor(value_str);
2168 if (replacement != null && !replacement.equals("")) {
2169 sort = replacement;
2170 }
2171 }
2172 else if(name_str.equals("buttonname") && value_str != null) {
2173 buttonname = value_str;
2174 }
2175 }
2176 }
2177 for (int i=0; i<num_nodes; i++) {
2178 Element classifier_element = (Element)classifier_children.item(i);
2179 NodeList option_children = classifier_element.getElementsByTagName(StaticStrings.OPTION_STR);
2180 for (int j=0; j<option_children.getLength(); j++) {
2181 Element option_element = (Element)option_children.item(j);
2182 String name_str = option_element.getAttribute(StaticStrings.NAME_ATTRIBUTE);
2183
2184 if (name_str.equals("metadata") && metadata != null) {
2185 option_element.setAttribute(StaticStrings.VALUE_ATTRIBUTE, metadata);
2186 }
2187 else if (name_str.equals("hfile") && hfile != null) {
2188 option_element.setAttribute(StaticStrings.VALUE_ATTRIBUTE, metadata + ".txt");
2189 }
2190 else if (name_str.equals("sort") && sort != null) {
2191 option_element.setAttribute(StaticStrings.VALUE_ATTRIBUTE, sort);
2192 }
2193 else if(name_str.equals("buttonname") && (buttonname == "" || buttonname == null)) {
2194 // No buttonname has been specified. Lets create one using the metadata as its value
2195 Element option = new_cfg_doc.createElement(StaticStrings.OPTION_STR);
2196 option.setAttribute(StaticStrings.NAME_ATTRIBUTE, "buttonname");
2197 option_element.setAttribute(StaticStrings.VALUE_ATTRIBUTE, metadata);
2198 classifier_element.appendChild(option);
2199 }
2200 }
2201 }
2202 }
2203
2204 private void updateCollectionCFG(File base_cfg, File new_cfg, String description, String email, String title)
2205 {
2206 boolean first_name = true;
2207 boolean first_extra = true;
2208
2209 // 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.
2210 try {
2211 BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(base_cfg), "UTF-8"));
2212 BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(new_cfg), "UTF-8"));
2213 String command = null;
2214 while((command = in.readLine()) != null) {
2215 if (command.length()==0) {
2216 // output a new line
2217 out.newLine();
2218 continue;
2219 }
2220 // We have to test the end of command for the special character '\'. If found, remove it and append the next line, then repeat.
2221 while(command.trim().endsWith("\\")) {
2222 command = command.substring(0, command.lastIndexOf("\\"));
2223 String next_line = in.readLine();
2224 if(next_line != null) {
2225 command = command + next_line;
2226 }
2227 }
2228 // commands can extend over more than one line so use the CommandTokenizer which takes care of that
2229 CommandTokenizer tokenizer = new CommandTokenizer(command, in, false);
2230 String command_type_str = tokenizer.nextToken().toLowerCase();
2231
2232 if (command_type_str.equals(StaticStrings.COLLECTIONMETADATA_STR)) {
2233 // read the whole thing in, but for collectionname, collectionextra, iconcollection, iconcollectionsmall we will ignore them
2234 StringBuffer new_command = new StringBuffer(command_type_str);
2235 String meta_name = tokenizer.nextToken();
2236 new_command.append(' ');
2237 new_command.append(meta_name);
2238 while (tokenizer.hasMoreTokens()) {
2239 new_command.append(' ');
2240 new_command.append(tokenizer.nextToken());
2241 }
2242 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)) {
2243 // dont save
2244 } else {
2245 write(out, new_command.toString());
2246 }
2247 new_command = null;
2248 continue;
2249 } // if collectionmeta
2250
2251 if (command_type_str.equals("classify")) {
2252 StringBuffer text = new StringBuffer(command_type_str);
2253 // Read in the classifier command watching for hfile, metadata and sort arguments.
2254 String buttonname = null;
2255 String hfile = null;
2256 String new_metadata = null;
2257 String old_metadata = null;
2258
2259 while(tokenizer.hasMoreTokens()) {
2260 String token = tokenizer.nextToken();
2261 if (token.equals("-hfile")) {
2262 if(tokenizer.hasMoreTokens()) {
2263 text.append(" ");
2264 text.append(token);
2265 token = tokenizer.nextToken();
2266 hfile = token;
2267 }
2268 }
2269 else if (token.equals("-metadata")) {
2270 if(tokenizer.hasMoreTokens()) {
2271 text.append(" ");
2272 text.append(token);
2273 String temp_metadata = tokenizer.nextToken();
2274 String replacement = ProfileXMLFileManager.getMetadataElementFor(temp_metadata);
2275 if (replacement != null && !replacement.equals("")) {
2276 token = replacement;
2277 old_metadata = temp_metadata;
2278 new_metadata = replacement;
2279 }
2280 else {
2281 token = temp_metadata;
2282 }
2283 temp_metadata = null;
2284 replacement = null;
2285 }
2286 }
2287 else if (token.equals("-sort")) {
2288 if(tokenizer.hasMoreTokens()) {
2289 text.append(" ");
2290 text.append(token);
2291 String temp_metadata = tokenizer.nextToken();
2292 String replacement = ProfileXMLFileManager.getMetadataElementFor(temp_metadata);
2293 if (replacement != null && !replacement.equals("")) {
2294 token = replacement;
2295 }
2296 else {
2297 token = temp_metadata;
2298 }
2299 temp_metadata = null;
2300 replacement = null;
2301 }
2302 }
2303 else if(token.equals("-buttonname")) {
2304 buttonname = token;
2305 }
2306 text.append(' ');
2307 text.append(token);
2308 token = null;
2309 }
2310
2311 // 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)!
2312 if(old_metadata != null && new_metadata != null && buttonname == null) {
2313 text.append(' ');
2314 text.append("-buttonname");
2315 text.append(' ');
2316 text.append(old_metadata);
2317 }
2318 command = text.toString();
2319 // Replace the hfile if we found it
2320 if(hfile != null && new_metadata != null) {
2321 command = command.replaceAll(hfile, new_metadata + ".txt");
2322 }
2323
2324 buttonname = null;
2325 hfile = null;
2326 new_metadata = null;
2327 old_metadata = null;
2328 write(out, command);
2329 } else {
2330 // the rest of the commands just want a string - we read in all the tokens from the tokeniser and get rid of it.
2331 StringBuffer new_command = new StringBuffer(command_type_str);
2332 while (tokenizer.hasMoreTokens()) {
2333 new_command.append(' ');
2334 new_command.append(tokenizer.nextToken());
2335 }
2336
2337 command = new_command.toString();
2338
2339 // 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.
2340 // we really want to build up the whole command here
2341 boolean format_command = command_type_str.equals("format");
2342 HashMap metadata_mapping = ProfileXMLFileManager.getMetadataMapping();
2343 if (metadata_mapping != null) {
2344 Iterator keys = metadata_mapping.keySet().iterator();
2345 while (keys.hasNext()) {
2346 String target = (String) keys.next();
2347 String replacement = (String) metadata_mapping.get(target);
2348 if (replacement != null && !replacement.equals("")) {
2349 if (format_command) {
2350 target = "\\[" + target + "\\]";
2351 replacement = "{Or}{[" + replacement + "]," + target + "}";
2352 }
2353 command = command.replaceAll(target, replacement);
2354 }
2355 }
2356 }
2357
2358 write(out, command);
2359 }
2360 tokenizer = null;
2361 }
2362 in.close();
2363 in = null;
2364 out.flush();
2365 out.close();
2366 out = null;
2367 }
2368 catch(Exception error) {
2369 DebugStream.printStackTrace(error);
2370 }
2371 // All done, I hope.
2372 }
2373
2374 private void write(BufferedWriter out, String message)
2375 throws Exception {
2376 out.write(message, 0, message.length());
2377 out.newLine();
2378 }
2379
2380
2381 /** The CollectionManager class is getting too confusing by half so I'll implement this TreeModelListener in a private class to make responsibility clear. */
2382 private class FMTreeModelListener
2383 implements TreeModelListener {
2384 /** 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.
2385 * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
2386 */
2387 public void treeNodesChanged(TreeModelEvent event) {
2388 if(collection != null) {
2389 collection.setSaved(false);
2390 collection.setFilesChanged(true);
2391 }
2392 }
2393 /** 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.
2394 * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
2395 */
2396 public void treeNodesInserted(TreeModelEvent event) {
2397 if(collection != null) {
2398 collection.setSaved(false);
2399 collection.setFilesChanged(true);
2400 }
2401 }
2402 /** 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.
2403 * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
2404 */
2405 public void treeNodesRemoved(TreeModelEvent event) {
2406 if(collection != null) {
2407 collection.setSaved(false);
2408 collection.setFilesChanged(true);
2409
2410 }
2411 }
2412 /** 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.
2413 * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
2414 */
2415 public void treeStructureChanged(TreeModelEvent event) {
2416 if(collection != null) {
2417 collection.setSaved(false);
2418 }
2419 }
2420 }
2421}
Note: See TracBrowser for help on using the repository browser.