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

Last change on this file since 4439 was 4439, checked in by jmt12, 21 years ago

Fixed incorrect use of File.separator in the path of something that will be found by the class loader.

  • Property svn:keywords set to Author Date Id Revision
File size: 56.9 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/" + 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 // Determine the local collection directory if any
574 String current_collection_directory = null;
575 if(collection != null) {
576 current_collection_directory = Utility.getCollectionDir(Gatherer.config.gsdl_path) + collection.getName();
577 }
578 // Create the workspace tree.
579 FileNode workspace_root = new FileNode("ABS_ROOT");
580 workspace_model = new FileSystemModel(workspace_root);
581 // Create and add Greenstone collections node.
582 // Starting at the collection directory of gsdl...
583 File start = new File(Utility.getCollectionDir(Gatherer.config.gsdl_path));
584 FileNode world_root = new FileNode(get("Tree.World"));
585 workspace_root.insert(world_root);
586 // For each of the children directories, which are collections...
587 File cols[] = start.listFiles();
588 ArrayTools.sort(cols);
589 // We add their import and gimport directories, but only if its not our current collection.
590 for(int i = 0; cols != null && i < cols.length; i++) {
591 if(collection == null || !current_collection_directory.equals(cols[i].getAbsolutePath())) {
592 File dirs[] = cols[i].listFiles();
593 ArrayTools.sort(dirs);
594 File import_dir = new File(cols[i], "gimport");
595 if(!import_dir.exists()) {
596 import_dir = new File(cols[i], "import");
597 }
598 if(import_dir.exists()) {
599 FileNode collection_root = new FileNode(import_dir, cols[i].getName(), true);
600 world_root.insert(collection_root);
601 collection_root = null;
602 }
603 import_dir = null;
604 }
605 }
606 // Create Local File space.
607 // Get all the available roots mounted on the system.
608 File roots[] = File.listRoots();
609 // If there is just one root use it as the tree root (linux)
610 if(roots != null) {
611 FileNode file_root;
612 String name = get("Tree.Root");
613 if(roots.length == 1) {
614 file_root = new FileNode(roots[0], name);
615 workspace_root.insert(file_root);
616 }
617 // Otherwise build a dummy node which has these nodes as children.
618 else {
619 file_root = new FileNode(name);
620 workspace_root.insert(file_root);
621 // Hopefully this does an alphabetic sort.
622 ArrayTools.sort(roots);
623 for(int i = 0; i < roots.length; i++) {
624 FileNode child_root = new FileNode(roots[i]);
625 file_root.insert(child_root);
626 child_root = null;
627 }
628 }
629 name = null;
630 file_root = null;
631 }
632 // If mirroring is enabled show the public and private caches.
633 if(Gatherer.config.get("workflow.mirror", false)) {
634 // Add Public workspace
635 FileNode public_root = new FileNode(new File(Utility.CACHE_DIR), get("Tree.Public"));
636 workspace_root.insert(public_root);
637 // Add Private workspace if a collection has been loaded.
638 if(ready()) {
639 FileNode private_root = new FileNode(new File(getCollectionCache()), get("Tree.Private"));
640 workspace_root.insert(private_root);
641 }
642 }
643 // Finally we retrieve and map any predefined special directories.
644 if(ready()) {
645 HashMap mappings = collection.getDirectoryMappings();
646 for(Iterator names = mappings.keySet().iterator(); names.hasNext(); ) {
647 String name = (String) names.next();
648 File file = (File) mappings.get(name);
649 FileNode special_root = new FileNode(file, name);
650 //workspace_root.insert(special_root);
651 SynchronizedTreeModelTools.insertNodeInto(workspace_model, workspace_root, special_root);
652 }
653 }
654 return workspace_model;
655 }
656 /** This method when called, creates a new GShell in order to run the import.pl script.
657 * @see org.greenstone.gatherer.Configuration
658 * @see org.greenstone.gatherer.Gatherer
659 * @see org.greenstone.gatherer.Message
660 * @see org.greenstone.gatherer.gui.BuildOptions
661 * @see org.greenstone.gatherer.shell.GShell
662 * @see org.greenstone.gatherer.shell.GShellListener
663 * @see org.greenstone.gatherer.shell.GShellProgressMonitor
664 * @see org.greenstone.gatherer.util.Utility
665 */
666 public void importCollection() {
667 if(!saved()) {
668 // Force save.
669 try {
670 SaveCollectionTask save_task = new SaveCollectionTask(collection);
671 save_task.setImportAfter(true);
672 save_task.start();
673 }
674 catch(Exception error) {
675 Gatherer.printStackTrace(error);
676 }
677 }
678 else {
679 importing = true;
680 String args[];
681 if(Utility.isWindows()) {
682 args = new String[6];
683 args[0] = Gatherer.config.perl_path;
684 args[1] = "-S";
685 args[2] = Gatherer.config.getScriptPath() + "import.pl";
686 args[3] = "-importdir";
687 args[4] = getCollectionImport();
688 args[5] = collection.getName();
689 }
690 else {
691 args = new String[4];
692 args[0] = Gatherer.config.getScriptPath() + "import.pl";
693 args[1] = "-importdir";
694 args[2] = getCollectionImport();
695 args[3] = collection.getName();
696 }
697 args = ArrayTools.add(args, collection.build_options.getImportValues());
698 GShell shell = new GShell(args, GShell.IMPORT, Message.BUILDING, this, import_monitor, GShell.GSHELL_IMPORT);
699 shell.addGShellListener(Gatherer.g_man.create_pane);
700 shell.start();
701 }
702 }
703 /** Attempts to load the given collection. Currently uses simple serialization of the collection class.
704 * @param location The path to the collection as a <strong>String</strong>.
705 * @see org.greenstone.gatherer.Configuration
706 * @see org.greenstone.gatherer.Gatherer
707 * @see org.greenstone.gatherer.Message
708 * @see org.greenstone.gatherer.collection.Collection
709 * @see org.greenstone.gatherer.msm.MetadataSetManager
710 * @see org.greenstone.gatherer.msm.MSMListener
711 * @see org.greenstone.gatherer.util.Utility
712 */
713 public boolean loadCollection(String location) {
714 ///ystem.err.println("Load Collection '" + location + "'");
715 String[] args2 = new String[1];
716 args2[0] = location;
717 boolean result = false;
718 // Check we have actually been given a .col file.
719 if(location.endsWith(".col")) {
720 File collection_file = new File(location);
721 // Ensure that the directory exists.
722 File collection_directory = collection_file.getParentFile();
723 if(collection_directory.exists()) {
724 String name = collection_directory.getName();
725 File lock_file = new File(collection_file.getParentFile(), LOCK_FILE);
726 // Now determine if a lock already exists on this collection.
727 int choice = LockFileDialog.YES_OPTION;
728 if(lock_file.exists()) {
729 LockFileDialog dialog = new LockFileDialog(Gatherer.g_man, name, lock_file);
730 choice = dialog.getChoice();
731 }
732 if(choice == LockFileDialog.YES_OPTION) {
733 try {
734 if(lock_file.exists()) {
735 lock_file.delete();
736 }
737 // Create a lock file.
738 createLockFile(lock_file);
739 // Open the collection file
740 collection = new Collection(collection_file);
741 collection.msm = new MetadataSetManager();
742 msm = collection.msm; // Legacy
743 collection.msm.load();
744 collection.cdm = new CollectionDesignManager();
745 collection.gdm = new GDMManager();
746 // Tell everyone that it worked.
747 Gatherer.println(get("Loading_Successful", name));
748 // Now we need to hook up classes that depend on messages from the metadata set manager to keep their content fresh.
749 collection.msm.addMSMListener(this);
750 // We're done. Let everyone know.
751 if(Gatherer.g_man != null) {
752 workspace_model = null;
753 Gatherer.g_man.collectionChanged(ready());
754 }
755 result = true;
756 } catch (Exception error) {
757 // There is obviously no existing collection present.
758 Gatherer.printStackTrace(error);
759 JOptionPane.showMessageDialog(Gatherer.g_man, get("Cannot_Open", args2), get("General.Error"), JOptionPane.ERROR_MESSAGE);
760 }
761 }
762 lock_file = null;
763 }
764 else {
765 JOptionPane.showMessageDialog(Gatherer.g_man, get("CollectionManager.File_Not_Found", args2), get("General.Error"), JOptionPane.ERROR_MESSAGE);
766 }
767 collection_directory = null;
768 }
769 else {
770 JOptionPane.showMessageDialog(Gatherer.g_man, get("Not_Col_File", args2), get("General.Error"), JOptionPane.ERROR_MESSAGE);
771 Gatherer.println("Not a Gatherer Collection.");
772 }
773 args2 = null;
774 return result;
775 }
776
777 public void makeCollection(String description, String email, String name, String title) {
778 // Run the mkcol command.
779 String command[];
780 if(Utility.isWindows()) {
781 if(description == null || email == null || title == null) {
782 command = new String[4];
783 }
784 else {
785 command = new String[10];
786 }
787 command[0] = Gatherer.config.perl_path;
788 command[1] = "-S";
789 command[2] = Gatherer.config.getScriptPath() + "mkcol.pl";
790 if(description == null || email == null || title == null) {
791 command[3] = name;
792 }
793 else {
794 command[3] = "-title";
795 command[4] = title;
796 command[5] = "-creator";
797 command[6] = email;
798 command[7] = "-about";
799 command[8] = description;
800 command[9] = name;
801 }
802 }
803 else {
804 if(description == null || email == null || title == null) {
805 command = new String[2];
806 command[0] = "mkcol.pl";
807 command[1] = name;
808 }
809 else {
810 command = new String[8];
811 command[0] = "mkcol.pl";
812 command[1] = "-title";
813 command[2] = title;
814 command[3] = "-creator";
815 command[4] = email;
816 command[5] = "-about";
817 command[6] = description;
818 command[7] = name;
819 }
820 }
821 GShell process = new GShell(command, GShell.NEW, Message.COLLECT, this, null, GShell.GSHELL_NEW);
822 process.addGShellListener(this);
823 process.run(); // Don't bother threading this... yet
824 }
825
826 /** 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.
827 * @param event A <strong>GShellEvent</strong> which contains a the message.
828 */
829 public synchronized void message(GShellEvent event) {
830 }
831 /** 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.
832 * @param event A <strong>MSMEvent</strong> containing details of the event that caused this message to be fired.
833 * @see org.greenstone.gatherer.collection.Collection
834 */
835 public void metadataChanged(MSMEvent event) {
836 // Again this change means we need to save the collection again.
837 collection.setSaved(false);
838 }
839 /** This call is fired whenever a process within a GShell created by this class begins.
840 * @param event A <strong>GShellEvent</strong> containing information about the GShell process.
841 * @see org.greenstone.gatherer.Gatherer
842 * @see org.greenstone.gatherer.gui.GUIManager
843 * @see org.greenstone.gatherer.shell.GShell
844 */
845 public synchronized void processBegun(GShellEvent event) {
846 ///ystem.err.println("ProcessBegun " + event.getType());
847 // If this is one of the types where we wish to lock user control
848 Gatherer.g_man.lockCollection((event.getType() == GShell.IMPORT), true);
849 }
850 /** This call is fired whenever a process within a GShell created by this class ends.
851 * @param event A <strong>GShellEvent</strong> containing information about the GShell process.
852 * @see org.greenstone.gatherer.Gatherer
853 * @see org.greenstone.gatherer.gui.GUIManager
854 * @see org.greenstone.gatherer.shell.GShell
855 */
856 public synchronized void processComplete(GShellEvent event) {
857 ///ystem.err.println("ProcessComplete " + event.getType());
858 Gatherer.g_man.lockCollection((event.getType() == GShell.IMPORT), false);
859 ///ystem.err.println("Recieved process complete event - " + event);
860 // If we were running an import, now run a build.
861 if(event.getType() == GShell.IMPORT && event.getStatus() != GShell.ERROR) {
862 // Finish import.
863 collection.setImported(true);
864 buildCollection();
865 }
866 // If we were running a build, now is when we move files across.
867 else if(event.getType() == GShell.BUILD && event.getStatus() != GShell.ERROR) {
868 ///ystem.err.println("Installing collection.");
869 installCollection();
870 collection.setBuilt(true);
871 // If we have a local library running (that we know about) then we ask it to add our newly create collection
872 ///ystem.err.println("Check if we should reset local server.");
873 if(Gatherer.config.exec_file != null) {
874 ///ystem.err.println("Local Library Found!");
875 Gatherer.g_man.preview_pane.configServer(GSDLSiteConfig.ADD_COMMAND + collection.getName());
876 }
877 //else {
878 ///ystem.err.println("GLI can't recognize a local library.");
879 //}
880 // Signal collection changed.
881 workspace_model = null;
882 Gatherer.g_man.collectionChanged(ready());
883 JOptionPane.showMessageDialog(Gatherer.g_man, get("Preview_Ready"), get("Preview_Ready_Title"), JOptionPane.INFORMATION_MESSAGE);
884 }
885 else if(event.getType() == GShell.BUILD && event.getStatus() == GShell.ERROR) {
886 JOptionPane.showMessageDialog(Gatherer.g_man, get("Preview_Ready_Failed"), get("Preview_Ready_Title"), JOptionPane.ERROR_MESSAGE);
887 }
888 }
889 /** Determine if the manager is ready for actions apon its collection.
890 * @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.
891 */
892 public boolean ready() {
893 if(collection != null) {
894 return true;
895 }
896 return false;
897 }
898 /** Called to refresh the models upon which the trees are based.
899 * @see org.greenstone.gatherer.collection.Collection
900 */
901 public void refreshTrees() {
902 }
903 /** This method associates the collection build monitor with the build monitor created in CreatePane.
904 * @param monitor A <strong>GShellProgressMonitor</strong> which we will use as the build monitor.
905 */
906 public void registerBuildMonitor(GShellProgressMonitor monitor) {
907 build_monitor = monitor;
908 }
909 /** This method associates the collection copy monitor with the copy monitor created in CreatePane.
910 * @param monitor A <strong>GShellProgressMonitor</strong> which we will use as the copy monitor.
911 */
912 public void registerCopyMonitor(GShellProgressMonitor monitor) {
913 copy_monitor = monitor;
914 }
915 /** This method associates the collection import monitor with the import monitor created in CreatePane.
916 * @param monitor A <strong>GShellProgressMonitor</strong> which we will use as the import monitor.
917 */
918 public void registerImportMonitor(GShellProgressMonitor monitor) {
919 import_monitor = monitor;
920 }
921 /** Remove a previously assigned special directory mapping.
922 * @param name The symbolic name of the special directory mapping to remove as a <strong>String</strong>.
923 * @return The <strong>File</strong> of the mapping removed.
924 */
925 public File removeDirectoryMapping(FileNode target) {
926 File file = null;
927 if(ready()) {
928 // Remove from collection, remembering file
929 file = collection.removeDirectoryMapping(target.toString());
930 // Update tree.
931 FileSystemModel model = (FileSystemModel) Gatherer.g_man.collection_pane.getWorkspaceTree().getModel();
932 SynchronizedTreeModelTools.removeNodeFromParent(model, target);
933 }
934 return file;
935 }
936 /** Used to check whether all open collections have a 'saved' state.
937 * @return A <i>boolean</i> which is <i>true</i> if the collection has been saved.
938 * @see org.greenstone.gatherer.collection.Collection
939 */
940 public boolean saved() {
941 boolean result = true;
942 if(collection != null) {
943 result = collection.getSaved();
944 }
945 return result;
946 }
947 /** Saves a collection by serializing it to file.
948 * @param close_after <i>true</i> to cause the Gatherer to close the collection once save is complete, <i>false</i> otherwise.
949 * @param exit_after <i>true</i> to cause the Gatherer to exit once save is complete, <i>false</i> otherwise.
950 * @see org.greenstone.gatherer.Gatherer
951 * @see org.greenstone.gatherer.Message
952 * @see org.greenstone.gatherer.gui.GUIManager
953 * @see org.greenstone.gatherer.gui.GConfigPane
954 * @see org.greenstone.gatherer.collection.Collection
955 */
956 public void saveCollection(boolean close_after, boolean exit_after) {
957 try {
958 SaveCollectionTask save_task = new SaveCollectionTask(collection, close_after, exit_after);
959 save_task.start();
960 }
961 catch(Exception error) {
962 Gatherer.printStackTrace(error);
963 }
964 }
965 /** Saves the current collection to a new filename, then restores the original collection. Finally opens the collection copy.
966 * @param name The name collection name.
967 */
968 public void saveCollectionAs(String name) {
969 // We need to do this in a separate thread so create a SaveCollectionAsTask
970 try {
971 SaveCollectionTask save_task = new SaveCollectionTask(collection, name);
972 save_task.start();
973 }
974 catch(Exception error) {
975 Gatherer.printStackTrace(error);
976 }
977 }
978
979 /** 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.
980 * @param event A <strong>MSMEvent</strong> containing details of the event that caused this message to be fired.
981 * @see org.greenstone.gatherer.collection.Collection
982 */
983 public void setChanged(MSMEvent event) {
984 // Invalidate saved
985 collection.setSaved(false);
986 }
987
988 /** Updates the given workspace tree model to reference the private cache of the currently loaded collection. */
989 public void updatePrivateWorkspace(DefaultTreeModel model) {
990 // Add Private workspace if a collection has been loaded.
991 if(ready() && !Gatherer.config.get("workflow.mirror", true)) {
992 FileNode root = (FileNode)model.getRoot();
993 // Remove old private workspace
994 FileNode old = (FileNode)model.getChild(root, 2);
995 model.removeNodeFromParent(old);
996 // Create and insert new.
997 FileNode private_workspace = new FileNode(new File(getCollectionCache()), get("Tree.Private"));
998 model.insertNodeInto(private_workspace, root, 2);
999 }
1000 }
1001 /** 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.
1002 * @param event A <strong>MSMEvent</strong> containing details of the event that caused this message to be fired.
1003 * @see org.greenstone.gatherer.collection.Collection
1004 */
1005 public void valueChanged(MSMEvent event) {
1006 collection.setSaved(false);
1007 }
1008 /** Used to retrive a value from the dictionary based on the key.
1009 * @param key A <strong>String</strong> indicating what value to retrieve.
1010 * @return A <strong>String</strong> representing the value.
1011 */
1012 private String get(String key) {
1013 return get(key, (String[])null);
1014 }
1015
1016 /** Used to retrive a value from the dictionary based on the key. */
1017 private String get(String key, String arg) {
1018 String[] args = new String[1];
1019 args[0] = arg;
1020 return get(key, args);
1021 }
1022
1023 /** Used to retrive a value from the dictionary based on the key, and an array of arguments.
1024 * @param key A <strong>String</strong> indicating what value to retrieve.
1025 * @param args A <strong>String[]</strong> of arguments to be inserted into the phrase.
1026 * @return A <strong>String</strong> representing the value.
1027 */
1028 private String get(String key, String args[]) {
1029 if(key.indexOf('.') == -1) {
1030 key = "CollectionManager." + key;
1031 }
1032 return Gatherer.dictionary.get(key, args);
1033 }
1034 /** Install collection by moving its files from building to index after a successful build.
1035 * @see org.greenstone.gatherer.Gatherer
1036 * @see org.greenstone.gatherer.util.Utility
1037 */
1038 private void installCollection() {
1039 Gatherer.println("Build complete. Moving files.");
1040
1041 try {
1042 // We have to ensure that the local library
1043 if(Gatherer.config.exec_file != null) {
1044 ///ystem.err.println("Local Library Found!");
1045 Gatherer.g_man.preview_pane.configServer(GSDLSiteConfig.RELEASE_COMMAND + collection.getName());
1046 }
1047
1048 File index_dir = new File(getCollectionIndex(), "temp.txt");
1049 index_dir = index_dir.getParentFile();
1050 Gatherer.println("Index = " + index_dir.getAbsolutePath());
1051
1052 if(index_dir.exists()) {
1053 Utility.delete(index_dir);
1054 }
1055
1056 if(index_dir.exists()) {
1057 throw(new Exception("Index directory cannot be removed."));
1058 }
1059
1060 File build_dir = new File(getCollectionBuild(), "temp.txt");
1061 build_dir = build_dir.getParentFile();
1062 Gatherer.println("Build = " + build_dir.getAbsolutePath());
1063 build_dir.renameTo(index_dir);
1064
1065 File new_build = new File(getCollectionBuild(), "temp.txt");
1066 new_build = new_build.getParentFile();
1067
1068 if(new_build.exists()) {
1069 throw(new Exception("Build directory cannot be moved."));
1070 }
1071
1072 new_build.mkdir();
1073 }
1074 catch (Exception exception) {
1075 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);
1076 }
1077 }
1078 /** Creates and dispatches a message given the initial details.
1079 * @param level An <i>int</i> indicating the message level for this message.
1080 * @param message A <strong>String</strong> which contains the payload of this message.
1081 * @see org.greenstone.gatherer.Log
1082 * @see org.greenstone.gatherer.Message
1083 */
1084 private void message(int level, String message) {
1085 Message msg = new Message(Message.COLLECT, level, message);
1086 if(Gatherer.g_man != null) {
1087 Gatherer.log.add(msg);
1088 } else {
1089 Gatherer.println(msg.toString());
1090 }
1091 }
1092
1093 private boolean searchArchivesForMetadata(File archive_directory) {
1094 /** @todo - ensure GreenstoneArchiveParser works as expected. */
1095 return true;
1096 }
1097
1098 private boolean searchForMetadata(File current_file) {
1099 boolean cancelled = false;
1100 if(current_file.isFile() && current_file.getName().equals(Utility.METADATA_XML)) {
1101 cancelled = collection.msm.searchForMetadata(null, new FileNode(current_file), false, true); // A dummy run only.
1102 }
1103 else {
1104 File[] children_files = current_file.listFiles();
1105 for(int i = 0; !cancelled && children_files != null && i < children_files.length; i++) {
1106 cancelled = searchForMetadata(children_files[i]);
1107 }
1108 }
1109 return cancelled;
1110 }
1111
1112 private void updateCollectionCFG(File base_cfg, File new_cfg, String description, String email, String title) {
1113 boolean first_name = true;
1114 boolean first_extra = true;
1115 String collection_path = (base_cfg.getParentFile().getParentFile()).getAbsolutePath();
1116
1117 HashMap mappings = collection.msm.profiler.getActions(collection_path);
1118
1119 // 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.
1120 try {
1121 BufferedReader in = new BufferedReader(new FileReader(base_cfg));
1122 BufferedWriter out = new BufferedWriter(new FileWriter(new_cfg, false)); // Overwrite whats there.
1123 String command = null;
1124 while((command = in.readLine()) != null) {
1125 // We have to test the end of command for the special character '\'. If found, remove it and append the next line, then repeat.
1126 while(command.trim().endsWith("\\")) {
1127 command = command.substring(0, command.lastIndexOf("\\"));
1128 String next_line = in.readLine();
1129 if(next_line != null) {
1130 command = command + next_line;
1131 }
1132 }
1133 ///ystem.err.println("Read: " + command);
1134 // Now we've finished parsing a line, determine what to do with it.
1135 String command_lc = command.toLowerCase();
1136 // We replace the creator string with our own.
1137 if(command_lc.startsWith(Utility.CFG_CREATOR)) {
1138 write(out, Utility.CFG_CREATOR + " " + email);
1139 }
1140 else if(command_lc.startsWith(Utility.CFG_MAINTAINER)) {
1141 write(out, Utility.CFG_MAINTAINER + " " + email);
1142 }
1143 else if(command_lc.startsWith(Utility.CFG_COLLECTIONMETA_COLLECTIONNAME)) {
1144 if(first_name) {
1145 write(out, Utility.CFG_COLLECTIONMETA_COLLECTIONNAME + " \"" + title + "\"");
1146 first_name = false;
1147 }
1148 }
1149 else if(command_lc.startsWith(Utility.CFG_COLLECTIONMETA_COLLECTIONEXTRA)) {
1150 if(first_extra) {
1151 write(out, Utility.CFG_COLLECTIONMETA_COLLECTIONEXTRA + " \"" + description + "\"");
1152 first_extra = false;
1153 }
1154 }
1155 else if(command_lc.startsWith(Utility.CFG_COLLECTIONMETA_ICONCOLLECTION)) {
1156 write(out, Utility.CFG_COLLECTIONMETA_ICONCOLLECTION + " \"\"");
1157 }
1158
1159 // 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.
1160 else if(special_case == SPECIAL_DLS && command_lc.equals("classify hierarchy -hfile azlist.txt -metadata azlist -sort title -buttonname title -hlist_at_top")) {
1161 write(out, "classify AZList -metadata dls.Title -buttonname Title");
1162 }
1163 else if(command_lc.startsWith(Utility.CFG_CLASSIFY)) {
1164 StringTokenizer tokenizer = new StringTokenizer(command);
1165 StringBuffer text = new StringBuffer(tokenizer.nextToken());
1166 // Read in the classifier command watching for hfile, metadata and sort arguments.
1167 String buttonname = null;
1168 String hfile = null;
1169 String new_metadata = null;
1170 String old_metadata = null;
1171 while(tokenizer.hasMoreTokens()) {
1172 String token = tokenizer.nextToken();
1173 if(token.equals(Utility.CFG_CLASSIFY_HFILE)) {
1174 if(tokenizer.hasMoreTokens()) {
1175 text.append(" ");
1176 text.append(token);
1177 token = tokenizer.nextToken();
1178 hfile = token;
1179 }
1180 }
1181 else if(token.equals(Utility.CFG_CLASSIFY_METADATA)) {
1182 if(tokenizer.hasMoreTokens()) {
1183 text.append(" ");
1184 text.append(token);
1185 String temp_metadata = tokenizer.nextToken();
1186 String replacement = (String) mappings.get(temp_metadata);
1187 if(replacement != null) {
1188 token = replacement;
1189 old_metadata = temp_metadata;
1190 new_metadata = replacement;
1191 }
1192 else {
1193 token = temp_metadata;
1194 }
1195 temp_metadata = null;
1196 replacement = null;
1197 }
1198 }
1199 else if(token.equals(Utility.CFG_CLASSIFY_SORT)) {
1200 if(tokenizer.hasMoreTokens()) {
1201 text.append(" ");
1202 text.append(token);
1203 String temp_metadata = tokenizer.nextToken();
1204 String replacement = (String) mappings.get(temp_metadata);
1205 if(replacement != null) {
1206 token = replacement;
1207 }
1208 else {
1209 token = temp_metadata;
1210 }
1211 temp_metadata = null;
1212 replacement = null;
1213 }
1214 }
1215 else if(token.equals(Utility.CFG_CLASSIFY_BUTTONNAME)) {
1216 buttonname = token;
1217 }
1218 text.append(' ');
1219 text.append(token);
1220 token = null;
1221 }
1222 tokenizer = null;
1223
1224 // 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)!
1225 if(old_metadata != null && new_metadata != null && buttonname == null) {
1226 text.append(' ');
1227 text.append(Utility.CFG_CLASSIFY_BUTTONNAME);
1228 text.append(' ');
1229 text.append(old_metadata);
1230 }
1231 command = text.toString();
1232 // Replace the hfile if we found it
1233 if(hfile != null && new_metadata != null) {
1234 command = command.replaceAll(hfile, new_metadata + ".txt");
1235 }
1236 buttonname = null;
1237 hfile = null;
1238 new_metadata = null;
1239 old_metadata = null;
1240 write(out, command);
1241 }
1242 else {
1243 // 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.
1244 boolean format_command = command_lc.startsWith(Utility.CFG_FORMAT);
1245 // Replace mapping strings
1246 if(mappings != null) {
1247 for(Iterator keys = mappings.keySet().iterator(); keys.hasNext(); ) {
1248 String target = (String) keys.next();
1249 String replacement = (String) mappings.get(target);
1250 if(format_command) {
1251 target = "\\[" + target + "\\]";
1252 replacement = "{Or}{[" + replacement + "]," + target + "}";
1253 }
1254 command = command.replaceAll(target, replacement);
1255 }
1256 }
1257 write(out, command);
1258 }
1259 }
1260 in.close();
1261 in = null;
1262 out.flush();
1263 out.close();
1264 out = null;
1265 }
1266 catch(Exception error) {
1267 Gatherer.printStackTrace(error);
1268 }
1269 // All done, I hope.
1270 }
1271
1272 private void write(BufferedWriter out, String message)
1273 throws Exception {
1274 ///ystem.err.println("Writing: " + message);
1275 out.write(message, 0, message.length());
1276 out.newLine();
1277 }
1278
1279 /** The CollectionManager class is getting too confusing by half so I'll implement this TreeModelListener in a private class to make responsibility clear. */
1280 private class FMTreeModelListener
1281 implements TreeModelListener {
1282 /** 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.
1283 * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
1284 */
1285 public void treeNodesChanged(TreeModelEvent event) {
1286 if(collection != null) {
1287 collection.setSaved(false);
1288 }
1289 }
1290 /** 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.
1291 * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
1292 */
1293 public void treeNodesInserted(TreeModelEvent event) {
1294 if(collection != null) {
1295 collection.setSaved(false);
1296 }
1297 }
1298 /** 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.
1299 * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
1300 */
1301 public void treeNodesRemoved(TreeModelEvent event) {
1302 if(collection != null) {
1303 collection.setSaved(false);
1304 }
1305 }
1306 /** 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.
1307 * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
1308 */
1309 public void treeStructureChanged(TreeModelEvent event) {
1310 if(collection != null) {
1311 collection.setSaved(false);
1312 }
1313 }
1314 }
1315}
Note: See TracBrowser for help on using the repository browser.