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

Last change on this file since 4368 was 4368, checked in by mdewsnip, 21 years ago

Undeprecated msm variable to prevent compile warnings.

  • Property svn:keywords set to Author Date Id Revision
File size: 56.7 KB
Line 
1package org.greenstone.gatherer.collection;
2/**
3 *#########################################################################
4 *
5 * A component of the Gatherer application, part of the Greenstone digital
6 * library suite from the New Zealand Digital Library Project at the
7 * University of Waikato, New Zealand.
8 *
9 * <BR><BR>
10 *
11 * Author: John Thompson, Greenstone Digital Library, University of Waikato
12 *
13 * <BR><BR>
14 *
15 * Copyright (C) 1999 New Zealand Digital Library Project
16 *
17 * <BR><BR>
18 *
19 * This program is free software; you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License as published by
21 * the Free Software Foundation; either version 2 of the License, or
22 * (at your option) any later version.
23 *
24 * <BR><BR>
25 *
26 * This program is distributed in the hope that it will be useful,
27 * but WITHOUT ANY WARRANTY; without even the implied warranty of
28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29 * GNU General Public License for more details.
30 *
31 * <BR><BR>
32 *
33 * You should have received a copy of the GNU General Public License
34 * along with this program; if not, write to the Free Software
35 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
36 *########################################################################
37 */
38import java.io.*;
39import java.lang.Class;
40import java.util.*;
41import javax.swing.*;
42import javax.swing.event.*;
43import javax.swing.tree.*;
44import org.greenstone.gatherer.Gatherer;
45import org.greenstone.gatherer.Message;
46import org.greenstone.gatherer.cdm.CollectionDesignManager;
47import org.greenstone.gatherer.cdm.CommandTokenizer;
48import org.greenstone.gatherer.collection.Collection;
49import org.greenstone.gatherer.collection.SaveCollectionTask;
50import org.greenstone.gatherer.file.FileNode;
51import org.greenstone.gatherer.file.FileSystemModel;
52import org.greenstone.gatherer.gui.LockFileDialog;
53import org.greenstone.gatherer.gui.MetaEditPane;
54import org.greenstone.gatherer.gui.NewCollectionMetadataPrompt;
55import org.greenstone.gatherer.msm.GDMManager;
56import org.greenstone.gatherer.msm.MetadataSet;
57import org.greenstone.gatherer.msm.MetadataSetManager;
58import org.greenstone.gatherer.msm.MSMEvent;
59import org.greenstone.gatherer.msm.MSMListener;
60import org.greenstone.gatherer.msm.MSMProfiler;
61import org.greenstone.gatherer.msm.MSMUtils;
62import org.greenstone.gatherer.shell.GShell;
63import org.greenstone.gatherer.shell.GShellEvent;
64import org.greenstone.gatherer.shell.GShellListener;
65import org.greenstone.gatherer.shell.GShellProgressMonitor;
66import org.greenstone.gatherer.undo.UndoManager;
67import org.greenstone.gatherer.util.ArrayTools;
68import org.greenstone.gatherer.util.GSDLSiteConfig;
69import org.greenstone.gatherer.util.MetadataXML;
70import org.greenstone.gatherer.util.SynchronizedTreeModelTools;
71import org.greenstone.gatherer.util.Utility;
72import org.w3c.dom.*;
73/** 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 resposible for firing appropriate event when significant changes have occured within the collection, and for creating a new metadata set manager as necessary.
74 * @author John Thompson
75 * @version 2.3
76 */
77public class CollectionManager
78 implements GShellListener, MSMListener {
79 /** A reference to the metadata set manager. */
80 public MetadataSetManager msm;
81 /** A reference to the undo manager. Although only one instance is shared between all collections, the undo queues are emptied between each. */
82 public UndoManager undo;
83 /** Are we currently in the process of building? */
84 private boolean building = false;
85 /** Are we currently in the process of importing? */
86 private boolean importing = false;
87 /** The collection this manager is managing! */
88 private Collection collection = null;
89 /** The collection_model. */
90 private FileSystemModel collection_model = null;
91 /** The workspace model. This becomes invalid on a collection change. */
92 private FileSystemModel workspace_model = null;
93 /** An inner class listener responsible for noting tree changes and resetting saved when they occur. */
94 private FMTreeModelListener fm_tree_model_listener = null;
95 /** The monitor resposible for parsing the build process. */
96 private GShellProgressMonitor build_monitor = null;
97 /** The monitor resposible for parsing the copy process. */
98 private GShellProgressMonitor copy_monitor = null;
99 /** The monitor resposible for parsing the import process. */
100 private GShellProgressMonitor import_monitor = null;
101
102 private int special_case = -1;
103 /** The name of the standard lock file. */
104 static final public String LOCK_FILE = "gatherer.lck";
105 static final public int NO_SPECIAL_CASE = -1;
106 static final public int SPECIAL_DLS = 0;
107 /** Constructor. */
108 public CollectionManager() {
109 // Initialisation.
110 this.building = false;
111 this.importing = false;
112 this.collection = null;
113 this.undo = new UndoManager();
114 }
115 /** Add a special directory mapping.
116 * @param name The name for this directory mapping as a <strong>String</strong>.
117 * @param file The directory this mapping maps to as a <strong>File</strong>.
118 */
119 public void addDirectoryMapping(String name, File file) {
120 if(ready()) {
121 // Update the information stored in the collection
122 collection.addDirectoryMapping(name, file);
123 // Now update the tree
124 FileSystemModel model = (FileSystemModel) Gatherer.g_man.collection_pane.getWorkspaceTree().getModel();
125 FileNode parent = (FileNode) model.getRoot();
126 FileNode target = new FileNode(file, name);
127 SynchronizedTreeModelTools.insertNodeInto(model, parent, target);
128 }
129 }
130 /** This method calls the builcol.pl scripts via a GShell so as to not lock up the processor.
131 * @see org.greenstone.gatherer.Configuration
132 * @see org.greenstone.gatherer.Gatherer
133 * @see org.greenstone.gatherer.Message
134 * @see org.greenstone.gatherer.collection.Collection
135 * @see org.greenstone.gatherer.gui.BuildOptions
136 * @see org.greenstone.gatherer.shell.GShell
137 * @see org.greenstone.gatherer.shell.GShellListener
138 * @see org.greenstone.gatherer.shell.GShellProgressMonitor
139 * @see org.greenstone.gatherer.util.Utility
140 */
141 public void buildCollection() {
142 Gatherer.println("Building collection");
143 building = true;
144
145 String args[];
146 if(Utility.isWindows()) {
147 args = new String[4];
148 args[0] = Gatherer.config.perl_path;
149 args[1] = "-S";
150 args[2] = Gatherer.config.getScriptPath() + "buildcol.pl";
151 args[3] = collection.getName();
152 }
153 else {
154 args = new String[2];
155 args[0] = Gatherer.config.getScriptPath() + "buildcol.pl";
156 args[1] = collection.getName();
157 }
158 args = ArrayTools.add(args, collection.build_options.getBuildValues());
159 GShell shell = new GShell(args, GShell.BUILD, Message.BUILDING, this, build_monitor, GShell.GSHELL_BUILD);
160 shell.addGShellListener(Gatherer.g_man.create_pane);
161 shell.start();
162 }
163 /** Used to determine whether the currently active collection has been built.
164 * @return A boolean indicating the built status of the collection.
165 */
166 public boolean built() {
167 if(collection != null) {
168 return collection.getBuilt();
169 }
170 return false;
171 }
172 /** Called to close the current collection and remove its lock file.
173 * @see org.greenstone.gatherer.Gatherer
174 * @see org.greenstone.gatherer.collection.Collection
175 * @see org.greenstone.gatherer.util.Utility
176 */
177 public void closeCollection() {
178 // Remove the lock on this file, then remove the collection.
179 File lock_file = new File(Utility.getCollectionDir(Gatherer.config.gsdl_path) + collection.getName() + File.separator + LOCK_FILE);
180 lock_file.delete();
181 collection.msm.destroy();
182 collection = null;
183 collection_model = null;
184 workspace_model = null;
185 undo.clear();
186 Gatherer.config.setCollectionConfiguration(null);
187 Gatherer.g_man.collectionChanged(false);
188 }
189
190 /** Method that is called whenever something has changed in the configuration of this collection. */
191 public void configurationChanged() {
192 if(collection != null) {
193 collection.setSaved(false);
194 }
195 }
196
197 /** 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 colection 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. */
198 public void createCollection(String description, String email, String name, String title, File base_collection_directory, ArrayList metadata_sets) {
199 special_case = NO_SPECIAL_CASE;
200 try {
201 // Create a progress monitor.
202 ProgressMonitor progress = new ProgressMonitor(Gatherer.g_man, get("Creating_New"), "mkcol.pl", 0, 7);
203 // Create the new collection.
204 makeCollection(description, email, name, title);
205 progress.setProgress(1);
206
207 // ACTIVE_DIR/gimport/
208 String a_dir = Utility.getCollectionDir(Gatherer.config.gsdl_path) + name + File.separator;
209
210 // Has to be done before creating greenstone directory metadata manager.
211 File gimport_dir_temp = new File(Utility.getImportDir(a_dir)+"temp.dat");
212 File gimport_dir = gimport_dir_temp.getParentFile();
213 gimport_dir.mkdirs();
214 if(progress != null) {
215 progress.setNote(get("Gimport_Created"));
216 }
217
218 // ACTIVE_DIR/gcache/
219 File gcache_dir_temp = new File(Utility.getCacheDir(a_dir)+"temp.dat");
220 File gcache_dir = gcache_dir_temp.getParentFile();
221 gcache_dir.mkdirs();
222 if(progress != null) {
223 progress.setNote(get("Gcache_Created"));
224 }
225
226 // ACTIVE_DIR/log/
227 File log_dir_temp = new File(Utility.getLogDir(a_dir)+"temp.dat");
228 File log_dir = log_dir_temp.getParentFile();
229 log_dir.mkdirs();
230 if(progress != null) {
231 progress.setNote(get("Log_Created"));
232 }
233
234 progress.setProgress(2);
235
236 // Now create the collection object around the directory.
237 collection = new Collection(new File(a_dir, name + ".col"));
238 collection.msm = new MetadataSetManager();
239 msm = collection.msm; // Legacy
240 collection.msm.load();
241 // Import default metadata sets if any.
242 for(int i = 0; metadata_sets != null && i < metadata_sets.size(); i++) {
243 MetadataSet metadata_set = (MetadataSet) metadata_sets.get(i);
244 collection.msm.importMDS(metadata_set.getFile(), false);
245 }
246
247 // Before we create the CollectionDesignManager we have to check if we are basing it upon some other collection.
248 if(base_collection_directory != null) {
249 // If so our first step is to correctly generate an import profile for our collection from this base collection.
250 // Try to import any existing metadata sets for this collection. Look in base_collection_directory/metadata and import any metadata sets found.
251 File base_metadata = new File(base_collection_directory, Utility.METADATA_DIR);
252 if(base_metadata.exists()) {
253 File[] possible_metadata_sets = base_metadata.listFiles();
254 for(int i = 0; possible_metadata_sets != null && i < possible_metadata_sets.length; i++) {
255 String filename = possible_metadata_sets[i].getName();
256 if(filename.endsWith(".mds")) {
257 ///ystem.err.println("Found a metadata set. Importing: " + possible_metadata_sets[i].getAbsolutePath());
258 collection.msm.importMDS(possible_metadata_sets[i], false);
259 }
260 }
261 }
262 // If no sets were imported, then create a new metadata with this new collections name. Note that if this is one of the 'big five' collections then I already know the importing mappings as well.
263 boolean skip_import_phase = false;
264 if(collection.msm.getSets().size() == 0) {
265 CollectionConfiguration col_con = new CollectionConfiguration(new File(base_collection_directory, Utility.CONFIG_DIR));
266 // If the source collection is one of the 'big five' then we know what the metadata set is.
267 String collection_name = col_con.getName();
268 // Demo collection - part of the DLS
269 if(collection_name.equals(Utility.COLLECTION_DEMO) || collection_name.equals(Utility.COLLECTION_DLS)) {
270 special_case = SPECIAL_DLS;
271 String demo_directory = (new File(base_collection_directory.getParentFile(), Utility.COLLECTION_DEMO_DIRECTORY)).getAbsolutePath();
272 String dls_directory = (new File(base_collection_directory.getParentFile(), Utility.COLLECTION_DLS_DIRECTORY)).getAbsolutePath();
273 // Add the dls.mds
274 collection.msm.importMDS(new File(Utility.METADATA_DIR + Utility.DLS_MDS), false);
275 // Add the mappings for the dls (even if its not present).
276 collection.msm.profiler.addAction(dls_directory, "AZList", "dls.AZList");
277 collection.msm.profiler.addAction(dls_directory, "Keyword", "dls.Keyword");
278 collection.msm.profiler.addAction(dls_directory, "Language", "dls.Language");
279 collection.msm.profiler.addAction(dls_directory, "Organization", "dls.Organization");
280 collection.msm.profiler.addAction(dls_directory, "Subject", "dls.Subject");
281 collection.msm.profiler.addAction(dls_directory, "Title", "dls.Title");
282 // Add the mappings for the demo dls (even if its not present).
283 collection.msm.profiler.addAction(demo_directory, "AZList", "dls.AZList");
284 collection.msm.profiler.addAction(demo_directory, "Keyword", "dls.Keyword");
285 collection.msm.profiler.addAction(demo_directory, "Language", "dls.Language");
286 collection.msm.profiler.addAction(demo_directory, "Organization", "dls.Organization");
287 collection.msm.profiler.addAction(demo_directory, "Subject", "dls.Subject");
288 collection.msm.profiler.addAction(demo_directory, "Title", "dls.Title");
289 // Skip the import phase
290 skip_import_phase = true;
291 }
292 // Prompt the user so that they can choose at least one initial metadata set. We're sneaky here and just create a ncm_prompt
293 else {
294 NewCollectionMetadataPrompt ncm_prompt = new NewCollectionMetadataPrompt();
295 // If cancelled then they really do mean to start a collection with no metadata sets.
296 if(!ncm_prompt.isCancelled()) {
297 ArrayList initial_sets = ncm_prompt.getSets();
298 for(int i = 0; initial_sets != null && i < initial_sets.size(); i++) {
299 MetadataSet metadata_set = (MetadataSet) initial_sets.get(i);
300 collection.msm.importMDS(metadata_set.getFile(), false);
301 metadata_set = null;
302 }
303 initial_sets = null;
304 }
305 ncm_prompt.dispose();
306 ncm_prompt = null;
307 }
308 }
309 // Do a dry metadata import run over the entire base collection, recording profile mappings. We do this by finding the archive files, and then iterating over them using the GreenstoneArchiveParser to retrieve metadata from them. We then process the importing of new metadata elements using the selectElement prompt used in a file action metadata import. However the big change is that we don't actually import any metadata, just create importing profiles.
310 File base_archives = new File(base_collection_directory, Utility.ARCHIVE_DIR);
311 if(!skip_import_phase && base_archives.exists()) {
312 ///ystem.err.println("Found archives directory.");
313 }
314 // Failing that we do a dummy run over the files in the collection.
315 else if(!skip_import_phase) {
316 ///ystem.err.println("No archives directory. Searching files for metadata.xml information.");
317 // Find the import directory
318 File base_import = new File(base_collection_directory, Utility.IMPORT_DIR);
319 if(!base_import.exists()) {
320 base_import = new File(base_collection_directory, Utility.OLD_IMPORT_DIR);
321 }
322 if(base_import.exists()) {
323 searchForMetadata(base_import);
324 }
325 // And if that fails then we must have been asked by Satan himself to build the very digital collections of hell, because they don't match any goodly greenstone collection I have ever seen, so you can't blame me if I can't import them.
326 }
327 // Now we update our collect.cfg
328 updateCollectionCFG(new File(base_collection_directory, Utility.CONFIG_DIR), new File(a_dir, Utility.CONFIG_DIR), description, email, title);
329 }
330
331 collection.cdm = new CollectionDesignManager();
332 collection.gdm = new GDMManager();
333
334 progress.setProgress(3);
335
336 // Has to be done after creating metadata set manager.
337 File gmeta_dir_temp = new File(getCollectionMetadata()+"temp.dat");
338 File gmeta_dir = gmeta_dir_temp.getParentFile();
339 gmeta_dir.mkdirs();
340 if(progress != null) {
341 progress.setNote("GMeta created");
342 }
343 progress.setProgress(4);
344
345 progress.setProgress(6);
346 // Register ourselves as being interested in what the msm has to say.
347 collection.msm.addMSMListener(this);
348 // Create a lock file.
349 File lock_file = new File(a_dir, LOCK_FILE);
350 FileOutputStream out = new FileOutputStream(lock_file);
351 out.write(LOCK_FILE.getBytes());
352 out.close();
353 out = null;
354 progress.setProgress(7);
355 String args[] = new String[1];
356 args[0] = name;
357 progress.setNote(get("Session_Ready", args));
358 progress.close();
359 }
360 catch (Exception error) {
361 Gatherer.printStackTrace(error);
362 }
363 // Done.
364 if(Gatherer.g_man != null) {
365 workspace_model = null;
366 Gatherer.g_man.collectionChanged(ready());
367 }
368 }
369
370 public void createLockFile(File destination) {
371 try {
372 Document default_lockfile = Utility.parse("xml" + File.separator + LOCK_FILE, true);
373 String user_name = System.getProperty("user.name");
374 Element person_element = (Element) MSMUtils.getNodeFromNamed(default_lockfile.getDocumentElement(), "User");
375 person_element.appendChild(default_lockfile.createTextNode(user_name));
376 person_element = null;
377 user_name = null;
378 String machine_name = Utility.getMachineName();
379 Element machine_element = (Element) MSMUtils.getNodeFromNamed(default_lockfile.getDocumentElement(), "Machine");
380 machine_element.appendChild(default_lockfile.createTextNode(machine_name));
381 machine_element = null;
382 machine_name = null;
383 String date_time = Utility.getDateString();
384 Element date_element = (Element) MSMUtils.getNodeFromNamed(default_lockfile.getDocumentElement(), "Date");
385 date_element.appendChild(default_lockfile.createTextNode(date_time));
386 date_element = null;
387 date_time = null;
388 Utility.export(default_lockfile, destination);
389 }
390 catch (Exception error) {
391 Gatherer.printStackTrace(error);
392 }
393 }
394
395 /** Method that is called whenever an element within a set is changed or modified. We want to mark the collection so that it needs saving again.
396 * @param event A <strong>MSMEvent</strong> containing details of the event that caused this message to be fired.
397 * @see org.greenstone.gatherer.collection.Collection
398 */
399 public void elementChanged(MSMEvent event) {
400 // This means the state of the collections has changed, so we should set saved to false.
401 collection.setSaved(false);
402 }
403 /** Used to retrieve the build options associated with the currently loaded collection. If none yet exist, default ones are created.
404 * @return A <strong>BuildOptions</strong> object containing the build options for the current collection.
405 * @see org.greenstone.gatherer.collection.Collection
406 */
407 public BuildOptions getBuildOptions() {
408 return collection.build_options;
409 }
410
411 /** Retrieve the current collection.
412 * @return The <strong>Collection</strong> itself.
413 */
414 public Collection getCollection() {
415 return collection;
416 }
417 /** Constructs the absolute filename of the collection archive directory, which should resemble "$GSDLHOME/collect/&lt;col_name&gt;/archive/"
418 * @return A <strong>String</strong> containing the filename.
419 * @see org.greenstone.gatherer.Configuration
420 * @see org.greenstone.gatherer.Gatherer
421 * @see org.greenstone.gatherer.collection.Collection
422 * @see org.greenstone.gatherer.util.Utility
423 */
424 public String getCollectionArchive() {
425 return Utility.getArchiveDir(Gatherer.config.gsdl_path, collection.getName());
426 }
427 /** Constructs the absolute filename of the collection building directory, which should resemble "$GSDLHOME/collect/&lt;col_name&gt;/building/"
428 * @return A <strong>String</strong> containing the filename.
429 * @see org.greenstone.gatherer.Configuration
430 * @see org.greenstone.gatherer.Gatherer
431 * @see org.greenstone.gatherer.collection.Collection
432 * @see org.greenstone.gatherer.util.Utility
433 */
434 public String getCollectionBuild() {
435 return Utility.getBuildDir(Utility.getCollectionDir(Gatherer.config.gsdl_path) + collection.getName() + File.separator);
436 }
437 /** Constructs the absolute filename of the collection cache directory, which should resemble "$GSDLHOME/collect/&lt;col_name&gt;/gcache/"
438 * @return A <strong>String</strong> containing the filename.
439 * @see org.greenstone.gatherer.Configuration
440 * @see org.greenstone.gatherer.Gatherer
441 * @see org.greenstone.gatherer.collection.Collection
442 * @see org.greenstone.gatherer.util.Utility
443 */
444 public String getCollectionCache() {
445 return Utility.getCacheDir(Utility.getCollectionDir(Gatherer.config.gsdl_path) + collection.getName() + File.separator);
446 }
447 /** Constructs the absolute filename of the collection config file, which should resemble "$GSDLHOME/collect/&lt;col_name&gt;/etc/collect.cfg"
448 * @return A <strong>String</strong> containing the filename.
449 * @see org.greenstone.gatherer.Configuration
450 * @see org.greenstone.gatherer.Gatherer
451 * @see org.greenstone.gatherer.collection.Collection
452 * @see org.greenstone.gatherer.util.Utility
453 */
454 public String getCollectionConfig() {
455 return Utility.getConfigDir(Utility.getCollectionDir(Gatherer.config.gsdl_path) + collection.getName() + File.separator);
456 }
457
458 /** Constructs the absolute filename of the collection directory, which should resemble "$GSDLHOME/collect/&lt;col_name&gt;"
459 * @return A <strong>String</strong> containing the directory name.
460 * @see org.greenstone.gatherer.Configuration
461 * @see org.greenstone.gatherer.Gatherer
462 * @see org.greenstone.gatherer.collection.Collection
463 * @see org.greenstone.gatherer.util.Utility
464 */
465 public String getCollectionDirectory() {
466 return Utility.getCollectionDir(Gatherer.config.gsdl_path) + collection.getName() + File.separator;
467 }
468
469 /** Constructs the absolute filename of the collection etc directory, which should resemble "$GSDLHOME/collect/&lt;col_name&gt;/etc/"
470 * @return A <strong>String</strong> containing the filename.
471 * @see org.greenstone.gatherer.Configuration
472 * @see org.greenstone.gatherer.Gatherer
473 * @see org.greenstone.gatherer.collection.Collection
474 * @see org.greenstone.gatherer.util.Utility
475 */
476 public String getCollectionEtc() {
477 return Utility.getEtcDir(Utility.getCollectionDir(Gatherer.config.gsdl_path) + collection.getName() + File.separator);
478 }
479 /** Constructs the absolute filename of the collection file, which should resemble "$GSDLHOME/collect/&lt;col_name&gt;/&lt;col_name&gt;.col"
480 * @return A <strong>String</strong> containing the filename.
481 * @see org.greenstone.gatherer.Configuration
482 * @see org.greenstone.gatherer.Gatherer
483 * @see org.greenstone.gatherer.collection.Collection
484 * @see org.greenstone.gatherer.util.Utility
485 */
486 public String getCollectionFilename() {
487 return Utility.getCollectionDir(Gatherer.config.gsdl_path) + collection.getName() + File.separator + collection.getName() + ".col";
488 }
489 /** Constructs the absolute filename of the collection import directory, which should resemble "$GSDLHOME/collect/&lt;col_name&gt;/gimport/"
490 * @return A <strong>String</strong> containing the filename.
491 * @see org.greenstone.gatherer.Configuration
492 * @see org.greenstone.gatherer.Gatherer
493 * @see org.greenstone.gatherer.collection.Collection
494 * @see org.greenstone.gatherer.util.Utility
495 */
496 public String getCollectionImport() {
497 return Utility.getImportDir(Utility.getCollectionDir(Gatherer.config.gsdl_path) + collection.getName() + File.separator);
498 }
499 /** Constructs the absolute filename of the collection index directory, which should resemble "$GSDLHOME/collect/&lt;col_name&gt;/index/"
500 * @return A <strong>String</strong> containing the filename.
501 * @see org.greenstone.gatherer.Configuration
502 * @see org.greenstone.gatherer.Gatherer
503 * @see org.greenstone.gatherer.collection.Collection
504 * @see org.greenstone.gatherer.util.Utility
505 */
506 public String getCollectionIndex() {
507 return Utility.getIndexDir(Utility.getCollectionDir(Gatherer.config.gsdl_path) + collection.getName() + File.separator);
508 }
509 /** Constructs the absolute filename of the collection log directory, which should resemble "$GSDLHOME/collect/&lt;col_name&gt;/log/"
510 * @return A <strong>String</strong> containing the filename.
511 * @see org.greenstone.gatherer.Configuration
512 * @see org.greenstone.gatherer.Gatherer
513 * @see org.greenstone.gatherer.collection.Collection
514 * @see org.greenstone.gatherer.util.Utility
515 */
516 public String getCollectionLog() {
517 return Utility.getLogDir(Utility.getCollectionDir(Gatherer.config.gsdl_path) + collection.getName() + File.separator);
518 }
519 /** Constructs the absolute filename of the collection metadata directory, which should resemble "$GSDLHOME/collect/&lt;col_name&gt;/metadata/"
520 * @return A <strong>String</strong> containing the filename.
521 * @see org.greenstone.gatherer.Configuration
522 * @see org.greenstone.gatherer.Gatherer
523 * @see org.greenstone.gatherer.collection.Collection
524 * @see org.greenstone.gatherer.util.Utility
525 */
526 public String getCollectionMetadata() {
527 return Utility.getMetadataDir(Utility.getCollectionDir(Gatherer.config.gsdl_path) + collection.getName() + File.separator);
528 }
529
530 public String getCollectionOldImport() {
531 return Utility.getCollectionDir(Gatherer.config.gsdl_path) + collection.getName() + File.separator + Utility.OLD_IMPORT_DIR;
532 }
533
534 /** This method either returns the title of the current collection, or a placeholder string of 'No Collection'.
535 * @return A <strong>String</strong> which represents what we wish to display for a collection title.
536 * @see org.greenstone.gatherer.collection.Collection
537 */
538 public String getCollectionTitle() {
539 if(collection != null) {
540 return collection.getTitle();
541 }
542 return get("Collection.No_Collection");
543 }
544
545 /** Retrieve the record set (tree model) associated with the current collection. */
546 public TreeModel getRecordSet() {
547 if(collection_model == null && collection != null) {
548 // Check if the gimport directory exists, and if so use it.
549 File gimport_directory = new File(getCollectionImport());
550 if(gimport_directory.exists()) {
551 // Generate a new FileSystemModel based on the collection gimport directory.
552 collection_model = new FileSystemModel(new FileNode(gimport_directory, false));
553 }
554 else {
555 ///ystem.err.println("No gimport directory exists.");
556 // Otherwise default to the import directory. If it doesn't exist, there aint much more I can do.
557 // Generate a new FileSystemModel based on the collection import directory.
558 collection_model = new FileSystemModel(new FileNode(new File(getCollectionOldImport()), false));
559 }
560 // Ensure that the manager is a change listener for the tree.
561 if(fm_tree_model_listener == null) {
562 fm_tree_model_listener = new FMTreeModelListener();
563 }
564 collection_model.addTreeModelListener(fm_tree_model_listener);
565 }
566 return collection_model;
567 }
568 /** Create and return the model behind the workspace tree. Quite an extensive method, as it must first map known greenstone collections, then the local file system and finally any public or private download workspaces. */
569 public TreeModel getWorkspace() {
570 if(workspace_model != null) {
571 return workspace_model;
572 }
573 // Create the workspace tree.
574 FileNode workspace_root = new FileNode("ABS_ROOT");
575 workspace_model = new FileSystemModel(workspace_root);
576 // Create and add Greenstone collections node.
577 // Starting at the collection directory of gsdl...
578 File start = new File(Utility.getCollectionDir(Gatherer.config.gsdl_path));
579 FileNode world_root = new FileNode(get("Tree.World"));
580 workspace_root.insert(world_root);
581 // For each of the children directories, which are collections...
582 File cols[] = start.listFiles();
583 ArrayTools.sort(cols);
584 // We add their import and gimport directories, but only if its not our current collection.
585 for(int i = 0; cols != null && i < cols.length; i++) {
586 if(collection == null || !(Utility.getCollectionDir(Gatherer.config.gsdl_path) + collection.getName()).equals(cols[i].getAbsolutePath())) {
587 File dirs[] = cols[i].listFiles();
588 ArrayTools.sort(dirs);
589 File import_dir = new File(cols[i], "gimport");
590 if(!import_dir.exists()) {
591 import_dir = new File(cols[i], "import");
592 }
593 if(import_dir.exists()) {
594 FileNode collection_root = new FileNode(import_dir, cols[i].getName(), true);
595 world_root.insert(collection_root);
596 collection_root = null;
597 }
598 import_dir = null;
599 }
600 }
601 // Create Local File space.
602 // Get all the available roots mounted on the system.
603 File roots[] = File.listRoots();
604 // If there is just one root use it as the tree root (linux)
605 if(roots != null) {
606 FileNode file_root;
607 String name = get("Tree.Root");
608 if(roots.length == 1) {
609 file_root = new FileNode(roots[0], name);
610 workspace_root.insert(file_root);
611 }
612 // Otherwise build a dummy node which has these nodes as
613 // children.
614 else {
615 file_root = new FileNode(name);
616 workspace_root.insert(file_root);
617 // Hopefully this does an alphabetic sort.
618 ArrayTools.sort(roots);
619 for(int i = 0; i < roots.length; i++) {
620 FileNode child_root = new FileNode(roots[i]);
621 file_root.insert(child_root);
622 child_root = null;
623 }
624 }
625 name = null;
626 file_root = null;
627 }
628 // If mirroring is enabled show the public and private caches.
629 if(Gatherer.config.get("workflow.mirror", false)) {
630 // Add Public workspace
631 FileNode public_root = new FileNode(new File(Utility.CACHE_DIR), get("Tree.Public"));
632 workspace_root.insert(public_root);
633 // Add Private workspace if a collection has been loaded.
634 if(ready()) {
635 FileNode private_root = new FileNode(new File(getCollectionCache()), get("Tree.Private"));
636 workspace_root.insert(private_root);
637 }
638 }
639 // Finally we retrieve and map any predefined special directories.
640 if(ready()) {
641 HashMap mappings = collection.getDirectoryMappings();
642 for(Iterator names = mappings.keySet().iterator(); names.hasNext(); ) {
643 String name = (String) names.next();
644 File file = (File) mappings.get(name);
645 FileNode special_root = new FileNode(file, name);
646 //workspace_root.insert(special_root);
647 SynchronizedTreeModelTools.insertNodeInto(workspace_model, workspace_root, special_root);
648 }
649 }
650 return workspace_model;
651 }
652 /** This method when called, creates a new GShell in order to run the import.pl script.
653 * @see org.greenstone.gatherer.Configuration
654 * @see org.greenstone.gatherer.Gatherer
655 * @see org.greenstone.gatherer.Message
656 * @see org.greenstone.gatherer.gui.BuildOptions
657 * @see org.greenstone.gatherer.shell.GShell
658 * @see org.greenstone.gatherer.shell.GShellListener
659 * @see org.greenstone.gatherer.shell.GShellProgressMonitor
660 * @see org.greenstone.gatherer.util.Utility
661 */
662 public void importCollection() {
663 if(!saved()) {
664 // Force save.
665 try {
666 SaveCollectionTask save_task = new SaveCollectionTask(collection);
667 save_task.setImportAfter(true);
668 save_task.start();
669 }
670 catch(Exception error) {
671 Gatherer.printStackTrace(error);
672 }
673 }
674 else {
675 importing = true;
676 String args[];
677 if(Utility.isWindows()) {
678 args = new String[6];
679 args[0] = Gatherer.config.perl_path;
680 args[1] = "-S";
681 args[2] = Gatherer.config.getScriptPath() + "import.pl";
682 args[3] = "-importdir";
683 args[4] = getCollectionImport();
684 args[5] = collection.getName();
685 }
686 else {
687 args = new String[4];
688 args[0] = Gatherer.config.getScriptPath() + "import.pl";
689 args[1] = "-importdir";
690 args[2] = getCollectionImport();
691 args[3] = collection.getName();
692 }
693 args = ArrayTools.add(args, collection.build_options.getImportValues());
694 GShell shell = new GShell(args, GShell.IMPORT, Message.BUILDING, this, import_monitor, GShell.GSHELL_IMPORT);
695 shell.addGShellListener(Gatherer.g_man.create_pane);
696 shell.start();
697 }
698 }
699 /** Attempts to load the given collection. Currently uses simple serialization of the collection class.
700 * @param location The path to the collection as a <strong>String</strong>.
701 * @see org.greenstone.gatherer.Configuration
702 * @see org.greenstone.gatherer.Gatherer
703 * @see org.greenstone.gatherer.Message
704 * @see org.greenstone.gatherer.collection.Collection
705 * @see org.greenstone.gatherer.msm.MetadataSetManager
706 * @see org.greenstone.gatherer.msm.MSMListener
707 * @see org.greenstone.gatherer.util.Utility
708 */
709 public boolean loadCollection(String location) {
710 ///ystem.err.println("Load Collection '" + location + "'");
711 String[] args2 = new String[1];
712 args2[0] = location;
713 boolean result = false;
714 // Check we have actually been given a .col file.
715 if(location.endsWith(".col")) {
716 File collection_file = new File(location);
717 // Ensure that the directory exists.
718 File collection_directory = collection_file.getParentFile();
719 if(collection_directory.exists()) {
720 String name = collection_directory.getName();
721 File lock_file = new File(collection_file.getParentFile(), LOCK_FILE);
722 // Now determine if a lock already exists on this collection.
723 int choice = LockFileDialog.YES_OPTION;
724 if(lock_file.exists()) {
725 LockFileDialog dialog = new LockFileDialog(Gatherer.g_man, name, lock_file);
726 choice = dialog.getChoice();
727 }
728 if(choice == LockFileDialog.YES_OPTION) {
729 try {
730 if(lock_file.exists()) {
731 lock_file.delete();
732 }
733 // Create a lock file.
734 createLockFile(lock_file);
735 // Open the collection file
736 collection = new Collection(collection_file);
737 collection.msm = new MetadataSetManager();
738 msm = collection.msm; // Legacy
739 collection.msm.load();
740 collection.cdm = new CollectionDesignManager();
741 collection.gdm = new GDMManager();
742 // Tell everyone that it worked.
743 Gatherer.println(get("Loading_Successful", name));
744 // Now we need to hook up classes that depend on messages from the metadata set manager to keep their content fresh.
745 collection.msm.addMSMListener(this);
746 // We're done. Let everyone know.
747 if(Gatherer.g_man != null) {
748 workspace_model = null;
749 Gatherer.g_man.collectionChanged(ready());
750 }
751 result = true;
752 } catch (Exception error) {
753 // There is obviously no existing collection present.
754 Gatherer.printStackTrace(error);
755 JOptionPane.showMessageDialog(Gatherer.g_man, get("Cannot_Open", args2), get("General.Error"), JOptionPane.ERROR_MESSAGE);
756 }
757 }
758 lock_file = null;
759 }
760 else {
761 JOptionPane.showMessageDialog(Gatherer.g_man, get("CollectionManager.File_Not_Found", args2), get("General.Error"), JOptionPane.ERROR_MESSAGE);
762 }
763 collection_directory = null;
764 }
765 else {
766 JOptionPane.showMessageDialog(Gatherer.g_man, get("Not_Col_File", args2), get("General.Error"), JOptionPane.ERROR_MESSAGE);
767 Gatherer.println("Not a Gatherer Collection.");
768 }
769 args2 = null;
770 return result;
771 }
772
773 public void makeCollection(String description, String email, String name, String title) {
774 // Run the mkcol command.
775 String command[];
776 if(Utility.isWindows()) {
777 if(description == null || email == null || title == null) {
778 command = new String[4];
779 }
780 else {
781 command = new String[10];
782 }
783 command[0] = Gatherer.config.perl_path;
784 command[1] = "-S";
785 command[2] = Gatherer.config.getScriptPath() + "mkcol.pl";
786 if(description == null || email == null || title == null) {
787 command[3] = name;
788 }
789 else {
790 command[3] = "-title";
791 command[4] = title;
792 command[5] = "-creator";
793 command[6] = email;
794 command[7] = "-about";
795 command[8] = description;
796 command[9] = name;
797 }
798 }
799 else {
800 if(description == null || email == null || title == null) {
801 command = new String[2];
802 command[0] = "mkcol.pl";
803 command[1] = name;
804 }
805 else {
806 command = new String[8];
807 command[0] = "mkcol.pl";
808 command[1] = "-title";
809 command[2] = title;
810 command[3] = "-creator";
811 command[4] = email;
812 command[5] = "-about";
813 command[6] = description;
814 command[7] = name;
815 }
816 }
817 GShell process = new GShell(command, GShell.NEW, Message.COLLECT, this, null, GShell.GSHELL_NEW);
818 process.addGShellListener(this);
819 process.run(); // Don't bother threading this... yet
820 }
821
822 /** 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.
823 * @param event A <strong>GShellEvent</strong> which contains a the message.
824 */
825 public synchronized void message(GShellEvent event) {
826 }
827 /** Called whenever the metadata value changes in some way, such as the addition of a new value. We want to mark the collection so that it needs saving again.
828 * @param event A <strong>MSMEvent</strong> containing details of the event that caused this message to be fired.
829 * @see org.greenstone.gatherer.collection.Collection
830 */
831 public void metadataChanged(MSMEvent event) {
832 // Again this change means we need to save the collection again.
833 collection.setSaved(false);
834 }
835 /** This call is fired whenever a process within a GShell created by this class begins.
836 * @param event A <strong>GShellEvent</strong> containing information about the GShell process.
837 * @see org.greenstone.gatherer.Gatherer
838 * @see org.greenstone.gatherer.gui.GUIManager
839 * @see org.greenstone.gatherer.shell.GShell
840 */
841 public synchronized void processBegun(GShellEvent event) {
842 ///ystem.err.println("ProcessBegun " + event.getType());
843 // If this is one of the types where we wish to lock user control
844 Gatherer.g_man.lockCollection((event.getType() == GShell.IMPORT), true);
845 }
846 /** This call is fired whenever a process within a GShell created by this class ends.
847 * @param event A <strong>GShellEvent</strong> containing information about the GShell process.
848 * @see org.greenstone.gatherer.Gatherer
849 * @see org.greenstone.gatherer.gui.GUIManager
850 * @see org.greenstone.gatherer.shell.GShell
851 */
852 public synchronized void processComplete(GShellEvent event) {
853 ///ystem.err.println("ProcessComplete " + event.getType());
854 Gatherer.g_man.lockCollection((event.getType() == GShell.IMPORT), false);
855 ///ystem.err.println("Recieved process complete event - " + event);
856 // If we were running an import, now run a build.
857 if(event.getType() == GShell.IMPORT && event.getStatus() != GShell.ERROR) {
858 // Finish import.
859 collection.setImported(true);
860 buildCollection();
861 }
862 // If we were running a build, now is when we move files across.
863 else if(event.getType() == GShell.BUILD && event.getStatus() != GShell.ERROR) {
864 ///ystem.err.println("Installing collection.");
865 installCollection();
866 collection.setBuilt(true);
867 // If we have a local library running (that we know about) then we ask it to add our newly create collection
868 ///ystem.err.println("Check if we should reset local server.");
869 if(Gatherer.config.exec_file != null) {
870 ///ystem.err.println("Local Library Found!");
871 Gatherer.g_man.preview_pane.configServer(GSDLSiteConfig.ADD_COMMAND + collection.getName());
872 }
873 //else {
874 ///ystem.err.println("GLI can't recognize a local library.");
875 //}
876 // Signal collection changed.
877 workspace_model = null;
878 Gatherer.g_man.collectionChanged(ready());
879 JOptionPane.showMessageDialog(Gatherer.g_man, get("Preview_Ready"), get("Preview_Ready_Title"), JOptionPane.INFORMATION_MESSAGE);
880 }
881 else if(event.getType() == GShell.BUILD && event.getStatus() == GShell.ERROR) {
882 JOptionPane.showMessageDialog(Gatherer.g_man, get("Preview_Ready_Failed"), get("Preview_Ready_Title"), JOptionPane.ERROR_MESSAGE);
883 }
884 }
885 /** Determine if the manager is ready for actions apon its collection.
886 * @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.
887 */
888 public boolean ready() {
889 if(collection != null) {
890 return true;
891 }
892 return false;
893 }
894 /** Called to refresh the models upon which the trees are based.
895 * @see org.greenstone.gatherer.collection.Collection
896 */
897 public void refreshTrees() {
898 }
899 /** This method associates the collection build monitor with the build monitor created in CreatePane.
900 * @param monitor A <strong>GShellProgressMonitor</strong> which we will use as the build monitor.
901 */
902 public void registerBuildMonitor(GShellProgressMonitor monitor) {
903 build_monitor = monitor;
904 }
905 /** This method associates the collection copy monitor with the copy monitor created in CreatePane.
906 * @param monitor A <strong>GShellProgressMonitor</strong> which we will use as the copy monitor.
907 */
908 public void registerCopyMonitor(GShellProgressMonitor monitor) {
909 copy_monitor = monitor;
910 }
911 /** This method associates the collection import monitor with the import monitor created in CreatePane.
912 * @param monitor A <strong>GShellProgressMonitor</strong> which we will use as the import monitor.
913 */
914 public void registerImportMonitor(GShellProgressMonitor monitor) {
915 import_monitor = monitor;
916 }
917 /** Remove a previously assigned special directory mapping.
918 * @param name The symbolic name of the special directory mapping to remove as a <strong>String</strong>.
919 * @return The <strong>File</strong> of the mapping removed.
920 */
921 public File removeDirectoryMapping(FileNode target) {
922 File file = null;
923 if(ready()) {
924 // Remove from collection, remembering file
925 file = collection.removeDirectoryMapping(target.toString());
926 // Update tree.
927 FileSystemModel model = (FileSystemModel) Gatherer.g_man.collection_pane.getWorkspaceTree().getModel();
928 SynchronizedTreeModelTools.removeNodeFromParent(model, target);
929 }
930 return file;
931 }
932 /** Used to check whether all open collections have a 'saved' state.
933 * @return A <i>boolean</i> which is <i>true</i> if the collection has been saved.
934 * @see org.greenstone.gatherer.collection.Collection
935 */
936 public boolean saved() {
937 boolean result = true;
938 if(collection != null) {
939 result = collection.getSaved();
940 }
941 return result;
942 }
943 /** Saves a collection by serializing it to file.
944 * @param close_after <i>true</i> to cause the Gatherer to close the collection once save is complete, <i>false</i> otherwise.
945 * @param exit_after <i>true</i> to cause the Gatherer to exit once save is complete, <i>false</i> otherwise.
946 * @see org.greenstone.gatherer.Gatherer
947 * @see org.greenstone.gatherer.Message
948 * @see org.greenstone.gatherer.gui.GUIManager
949 * @see org.greenstone.gatherer.gui.GConfigPane
950 * @see org.greenstone.gatherer.collection.Collection
951 */
952 public void saveCollection(boolean close_after, boolean exit_after) {
953 try {
954 SaveCollectionTask save_task = new SaveCollectionTask(collection, close_after, exit_after);
955 save_task.start();
956 }
957 catch(Exception error) {
958 Gatherer.printStackTrace(error);
959 }
960 }
961 /** Saves the current collection to a new filename, then restores the original collection. Finally opens the collection copy.
962 * @param name The name collection name.
963 */
964 public void saveCollectionAs(String name) {
965 // We need to do this in a separate thread so create a SaveCollectionAsTask
966 try {
967 SaveCollectionTask save_task = new SaveCollectionTask(collection, name);
968 save_task.start();
969 }
970 catch(Exception error) {
971 Gatherer.printStackTrace(error);
972 }
973 }
974
975 /** Method that is called whenever the metadata set collection changes in some way, such as the addition of a new set or the merging of two sets. We want to mark the collection so that it needs saving again.
976 * @param event A <strong>MSMEvent</strong> containing details of the event that caused this message to be fired.
977 * @see org.greenstone.gatherer.collection.Collection
978 */
979 public void setChanged(MSMEvent event) {
980 // Invalidate saved
981 collection.setSaved(false);
982 }
983
984 /** Updates the given workspace tree model to reference the private cache of the currently loaded collection. */
985 public void updatePrivateWorkspace(DefaultTreeModel model) {
986 // Add Private workspace if a collection has been loaded.
987 if(ready() && !Gatherer.config.get("workflow.mirror", true)) {
988 FileNode root = (FileNode)model.getRoot();
989 // Remove old private workspace
990 FileNode old = (FileNode)model.getChild(root, 2);
991 model.removeNodeFromParent(old);
992 // Create and insert new.
993 FileNode private_workspace = new FileNode(new File(getCollectionCache()), get("Tree.Private"));
994 model.insertNodeInto(private_workspace, root, 2);
995 }
996 }
997 /** Called whenever the value tree of an metadata element changes in some way, such as the addition of a new value. We want to mark the collection so that it needs saving again.
998 * @param event A <strong>MSMEvent</strong> containing details of the event that caused this message to be fired.
999 * @see org.greenstone.gatherer.collection.Collection
1000 */
1001 public void valueChanged(MSMEvent event) {
1002 collection.setSaved(false);
1003 }
1004 /** Used to retrive a value from the dictionary based on the key.
1005 * @param key A <strong>String</strong> indicating what value to retrieve.
1006 * @return A <strong>String</strong> representing the value.
1007 */
1008 private String get(String key) {
1009 return get(key, (String[])null);
1010 }
1011
1012 /** Used to retrive a value from the dictionary based on the key. */
1013 private String get(String key, String arg) {
1014 String[] args = new String[1];
1015 args[0] = arg;
1016 return get(key, args);
1017 }
1018
1019 /** Used to retrive a value from the dictionary based on the key, and an array of arguments.
1020 * @param key A <strong>String</strong> indicating what value to retrieve.
1021 * @param args A <strong>String[]</strong> of arguments to be inserted into the phrase.
1022 * @return A <strong>String</strong> representing the value.
1023 */
1024 private String get(String key, String args[]) {
1025 if(key.indexOf('.') == -1) {
1026 key = "CollectionManager." + key;
1027 }
1028 return Gatherer.dictionary.get(key, args);
1029 }
1030 /** Install collection by moving its files from building to index after a successful build.
1031 * @see org.greenstone.gatherer.Gatherer
1032 * @see org.greenstone.gatherer.util.Utility
1033 */
1034 private void installCollection() {
1035 Gatherer.println("Build complete. Moving files.");
1036
1037 try {
1038 // We have to ensure that the local library
1039 if(Gatherer.config.exec_file != null) {
1040 ///ystem.err.println("Local Library Found!");
1041 Gatherer.g_man.preview_pane.configServer(GSDLSiteConfig.RELEASE_COMMAND + collection.getName());
1042 }
1043
1044 File index_dir = new File(getCollectionIndex(), "temp.txt");
1045 index_dir = index_dir.getParentFile();
1046 Gatherer.println("Index = " + index_dir.getAbsolutePath());
1047
1048 if(index_dir.exists()) {
1049 Utility.delete(index_dir);
1050 }
1051
1052 if(index_dir.exists()) {
1053 throw(new Exception("Index directory cannot be removed."));
1054 }
1055
1056 File build_dir = new File(getCollectionBuild(), "temp.txt");
1057 build_dir = build_dir.getParentFile();
1058 Gatherer.println("Build = " + build_dir.getAbsolutePath());
1059 build_dir.renameTo(index_dir);
1060
1061 File new_build = new File(getCollectionBuild(), "temp.txt");
1062 new_build = new_build.getParentFile();
1063
1064 if(new_build.exists()) {
1065 throw(new Exception("Build directory cannot be moved."));
1066 }
1067
1068 new_build.mkdir();
1069 }
1070 catch (Exception exception) {
1071 JOptionPane.showMessageDialog(Gatherer.g_man, "Exception detected during collection install.\nMost likely caused by Windows or Local Library holding locks on files:\n" + exception.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
1072 }
1073 }
1074 /** Creates and dispatches a message given the initial details.
1075 * @param level An <i>int</i> indicating the message level for this message.
1076 * @param message A <strong>String</strong> which contains the payload of this message.
1077 * @see org.greenstone.gatherer.Log
1078 * @see org.greenstone.gatherer.Message
1079 */
1080 private void message(int level, String message) {
1081 Message msg = new Message(Message.COLLECT, level, message);
1082 if(Gatherer.g_man != null) {
1083 Gatherer.log.add(msg);
1084 } else {
1085 Gatherer.println(msg.toString());
1086 }
1087 }
1088
1089 private boolean searchArchivesForMetadata(File archive_directory) {
1090 /** @todo - ensure GreenstoneArchiveParser works as expected. */
1091 return true;
1092 }
1093
1094 private boolean searchForMetadata(File current_file) {
1095 boolean cancelled = false;
1096 if(current_file.isFile() && current_file.getName().equals(Utility.METADATA_XML)) {
1097 cancelled = collection.msm.searchForMetadata(null, new FileNode(current_file), false, true); // A dummy run only.
1098 }
1099 else {
1100 File[] children_files = current_file.listFiles();
1101 for(int i = 0; !cancelled && children_files != null && i < children_files.length; i++) {
1102 cancelled = searchForMetadata(children_files[i]);
1103 }
1104 }
1105 return cancelled;
1106 }
1107
1108 private void updateCollectionCFG(File base_cfg, File new_cfg, String description, String email, String title) {
1109 boolean first_name = true;
1110 boolean first_extra = true;
1111 String collection_path = (base_cfg.getParentFile().getParentFile()).getAbsolutePath();
1112
1113 HashMap mappings = collection.msm.profiler.getActions(collection_path);
1114
1115 // 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.
1116 try {
1117 BufferedReader in = new BufferedReader(new FileReader(base_cfg));
1118 BufferedWriter out = new BufferedWriter(new FileWriter(new_cfg, false)); // Overwrite whats there.
1119 String command = null;
1120 while((command = in.readLine()) != null) {
1121 // We have to test the end of command for the special character '\'. If found, remove it and append the next line, then repeat.
1122 while(command.trim().endsWith("\\")) {
1123 command = command.substring(0, command.lastIndexOf("\\"));
1124 String next_line = in.readLine();
1125 if(next_line != null) {
1126 command = command + next_line;
1127 }
1128 }
1129 ///ystem.err.println("Read: " + command);
1130 // Now we've finished parsing a line, determine what to do with it.
1131 String command_lc = command.toLowerCase();
1132 // We replace the creator string with our own.
1133 if(command_lc.startsWith(Utility.CFG_CREATOR)) {
1134 write(out, Utility.CFG_CREATOR + " " + email);
1135 }
1136 else if(command_lc.startsWith(Utility.CFG_MAINTAINER)) {
1137 write(out, Utility.CFG_MAINTAINER + " " + email);
1138 }
1139 else if(command_lc.startsWith(Utility.CFG_COLLECTIONMETA_COLLECTIONNAME)) {
1140 if(first_name) {
1141 write(out, Utility.CFG_COLLECTIONMETA_COLLECTIONNAME + " \"" + title + "\"");
1142 first_name = false;
1143 }
1144 }
1145 else if(command_lc.startsWith(Utility.CFG_COLLECTIONMETA_COLLECTIONEXTRA)) {
1146 if(first_extra) {
1147 write(out, Utility.CFG_COLLECTIONMETA_COLLECTIONEXTRA + " \"" + description + "\"");
1148 first_extra = false;
1149 }
1150 }
1151 else if(command_lc.startsWith(Utility.CFG_COLLECTIONMETA_ICONCOLLECTION)) {
1152 write(out, Utility.CFG_COLLECTIONMETA_ICONCOLLECTION + " \"\"");
1153 }
1154
1155 // Just before we try more general parsing there are the special cases to check. These are explicit changes required by some collections to produce sensible results.
1156 else if(special_case == SPECIAL_DLS && command_lc.equals("classify hierarchy -hfile azlist.txt -metadata azlist -sort title -buttonname title -hlist_at_top")) {
1157 write(out, "classify AZList -metadata dls.Title -buttonname Title");
1158 }
1159 else if(command_lc.startsWith(Utility.CFG_CLASSIFY)) {
1160 StringTokenizer tokenizer = new StringTokenizer(command);
1161 StringBuffer text = new StringBuffer(tokenizer.nextToken());
1162 // Read in the classifier command watching for hfile, metadata and sort arguments.
1163 String buttonname = null;
1164 String hfile = null;
1165 String new_metadata = null;
1166 String old_metadata = null;
1167 while(tokenizer.hasMoreTokens()) {
1168 String token = tokenizer.nextToken();
1169 if(token.equals(Utility.CFG_CLASSIFY_HFILE)) {
1170 if(tokenizer.hasMoreTokens()) {
1171 text.append(" ");
1172 text.append(token);
1173 token = tokenizer.nextToken();
1174 hfile = token;
1175 }
1176 }
1177 else if(token.equals(Utility.CFG_CLASSIFY_METADATA)) {
1178 if(tokenizer.hasMoreTokens()) {
1179 text.append(" ");
1180 text.append(token);
1181 String temp_metadata = tokenizer.nextToken();
1182 String replacement = (String) mappings.get(temp_metadata);
1183 if(replacement != null) {
1184 token = replacement;
1185 old_metadata = temp_metadata;
1186 new_metadata = replacement;
1187 }
1188 else {
1189 token = temp_metadata;
1190 }
1191 temp_metadata = null;
1192 replacement = null;
1193 }
1194 }
1195 else if(token.equals(Utility.CFG_CLASSIFY_SORT)) {
1196 if(tokenizer.hasMoreTokens()) {
1197 text.append(" ");
1198 text.append(token);
1199 String temp_metadata = tokenizer.nextToken();
1200 String replacement = (String) mappings.get(temp_metadata);
1201 if(replacement != null) {
1202 token = replacement;
1203 }
1204 else {
1205 token = temp_metadata;
1206 }
1207 temp_metadata = null;
1208 replacement = null;
1209 }
1210 }
1211 else if(token.equals(Utility.CFG_CLASSIFY_BUTTONNAME)) {
1212 buttonname = token;
1213 }
1214 text.append(' ');
1215 text.append(token);
1216 token = null;
1217 }
1218 tokenizer = null;
1219
1220 // 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)!
1221 if(old_metadata != null && new_metadata != null && buttonname == null) {
1222 text.append(' ');
1223 text.append(Utility.CFG_CLASSIFY_BUTTONNAME);
1224 text.append(' ');
1225 text.append(old_metadata);
1226 }
1227 command = text.toString();
1228 // Replace the hfile if we found it
1229 if(hfile != null && new_metadata != null) {
1230 command = command.replaceAll(hfile, new_metadata + ".txt");
1231 }
1232 buttonname = null;
1233 hfile = null;
1234 new_metadata = null;
1235 old_metadata = null;
1236 write(out, command);
1237 }
1238 else {
1239 // 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.
1240 boolean format_command = command_lc.startsWith(Utility.CFG_FORMAT);
1241 // Replace mapping strings
1242 if(mappings != null) {
1243 for(Iterator keys = mappings.keySet().iterator(); keys.hasNext(); ) {
1244 String target = (String) keys.next();
1245 String replacement = (String) mappings.get(target);
1246 if(format_command) {
1247 target = "\\[" + target + "\\]";
1248 replacement = "{Or}{[" + replacement + "]," + target + "}";
1249 }
1250 command = command.replaceAll(target, replacement);
1251 }
1252 }
1253 write(out, command);
1254 }
1255 }
1256 in.close();
1257 in = null;
1258 out.flush();
1259 out.close();
1260 out = null;
1261 }
1262 catch(Exception error) {
1263 Gatherer.printStackTrace(error);
1264 }
1265 // All done, I hope.
1266 }
1267
1268 private void write(BufferedWriter out, String message)
1269 throws Exception {
1270 ///ystem.err.println("Writing: " + message);
1271 out.write(message, 0, message.length());
1272 out.newLine();
1273 }
1274
1275 /** The CollectionManager class is getting too confusing by half so I'll implement this TreeModelListener in a private class to make responsibility clear. */
1276 private class FMTreeModelListener
1277 implements TreeModelListener {
1278 /** 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.
1279 * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
1280 */
1281 public void treeNodesChanged(TreeModelEvent event) {
1282 if(collection != null) {
1283 collection.setSaved(false);
1284 }
1285 }
1286 /** 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.
1287 * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
1288 */
1289 public void treeNodesInserted(TreeModelEvent event) {
1290 if(collection != null) {
1291 collection.setSaved(false);
1292 }
1293 }
1294 /** 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.
1295 * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
1296 */
1297 public void treeNodesRemoved(TreeModelEvent event) {
1298 if(collection != null) {
1299 collection.setSaved(false);
1300 }
1301 }
1302 /** 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.
1303 * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
1304 */
1305 public void treeStructureChanged(TreeModelEvent event) {
1306 if(collection != null) {
1307 collection.setSaved(false);
1308 }
1309 }
1310 }
1311}
Note: See TracBrowser for help on using the repository browser.