/** *######################################################################### * * A component of the Gatherer application, part of the Greenstone digital * library suite from the New Zealand Digital Library Project at the * University of Waikato, New Zealand. * *

* * Author: John Thompson, Greenstone Digital Library, University of Waikato * *

* * Copyright (C) 1999 New Zealand Digital Library Project * *

* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * *

* * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * *

* * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *######################################################################## */ package org.greenstone.gatherer.collection; import java.io.*; import java.util.*; import javax.swing.*; import org.greenstone.gatherer.Configuration; import org.greenstone.gatherer.DebugStream; import org.greenstone.gatherer.Gatherer; import org.greenstone.gatherer.collection.Collection; import org.greenstone.gatherer.util.Utility; /** The actually saving of a collection must run in a thread other than the AWTEvent thread, or else the save progress box will never get updated. To that end this class provides a threaded save method, which saves the various parts of the collection to the appropriate disk location. * @author John Thompson, Greenstone Digital Library, University of Waikato * @version 2.3 */ public class SaveCollectionTask extends Thread { private boolean close_after = false; /** Should we exit the Gatherer once this save is complete. */ private boolean exit_after = false; /** Do we run the import scripts once this save is complete. */ private boolean import_after = false; /** The current collection. */ private Collection collection = null; /** The filename of the collection we are saving. */ private String name = null; static final private int CLOSE_COLLECTION = 0; static final private int COLLECTION_COPIED = 1; static final private int COLLECTION_SAVED = 2; static final private int COLLECTION_CFG_SAVED = 3; static final private int COPY_COLLECTION = 4; static final private int MAKE_COLLECTION = 5; static final private int METADATA_SAVED = 6; static final private int METADATA_XML_SAVED = 7; static final private int OPEN_COLLECTION = 8; static final private int RESTORE_COLLECTION = 9; /** Constructor. * @param collection The Collection we are saving. * @see org.greenstone.gatherer.collection.Collection */ public SaveCollectionTask(Collection collection) { this.collection = collection; } /** Constructor. * @param exit_after true to cause the Gatherer to exit once save is complete, false otherwise. */ public SaveCollectionTask(Collection collection, boolean close_after, boolean exit_after) { this.close_after = close_after; this.collection = collection; this.exit_after = exit_after; } /** Constructor. * @param name The filename of the collection we are saving as. */ public SaveCollectionTask(Collection collection, String name) { this.collection = collection; this.name = name; } /**

This method, when created in a forked process by start(), performs the actions necessary to save a collection. If this is a regular save it saves the state of the current collection, ensuring all files, metadata files, and configuration files are written to disk. If, instead, this is a "Save As" action then there as several more steps involved:

*

1. Perform a regular collection save on what we will later refer to as the origin collection.

*

2. Call CollectionManager.makeCollection() to create the collection structure to save into (copied collection).

*

3. Copy files from the origin to the copied collections (except special collection files ending with ~).

*

4. Restore origin collection by undoing file copy actions and removing the ~ from the end of collection files.

*

5. Close the origin collection.

*

6. Open the copied collection.

*

Of course all of this takes a while, and depends on several other bits of code to work properly.

. * @see org.greenstone.gatherer.collection.Collection * @see org.greenstone.gatherer.gui.GUIManager * @see org.greenstone.gatherer.util.Utility */ public void run() { // Change cursor to hourglass. Gatherer.g_man.wait(true); // Create progress monitor box. It will display itself as necessary. // WARNING: ProgressMonitors seem to be extremely dodgy, and are not recommended! // ProgressMonitor spd = new ProgressMonitor(Gatherer.g_man, Dictionary.get("SaveProgressDialog.Title", collection.getName()), null, 0, 100); // spd.setMillisToDecideToPopup(100); // spd.setMillisToPopup(100); // 0. Force all remaining metadata.xml files to load. // 1. Perform a regular collection save on what we will later refer to as the origin collection. ///ystem.err.println("1. Save origin."); String tmp_loc = Gatherer.c_man.getCollectionFilename(); String args[] = new String[1]; args[0] = collection.getName() + ".col"; try { // Block until all of the metadata files have been read in. collection.gdm.waitUntilComplete(); // Write out the metadata xml files. The destroy below is meant to do this, but never does. collection.gdm.save(); // spd.setProgress(getValue(METADATA_XML_SAVED)); File file = new File(tmp_loc); // Create backup if(file.exists()) { File backup = new File(tmp_loc + "~"); backup.deleteOnExit(); if(!file.renameTo(backup)) { DebugStream.println("Error in CollectionManager.load(): FileRenamedException"); } } // Carry on. collection.save(); // spd.setProgress(getValue(COLLECTION_SAVED)); // Write out the collection configuration file. Gatherer.g_man.design_pane.saveConfiguration(); // spd.setProgress(getValue(COLLECTION_CFG_SAVED)); // Write out the metadata files. Gatherer.c_man.msm.save(); // spd.setProgress(getValue(METADATA_SAVED)); collection.setSaved(true); } catch (Exception error) { DebugStream.printStackTrace(error); } // Now we check whether we've finished, or is this a Save As action, in which case we've got miles to go. if(name != null) { // 2. Call CollectionManager.makeCollection() to create the collection structure to save into (copied collection). ///ystem.err.println("2. Make copy."); Gatherer.c_man.createCollection(null, null, name, null, null, null); // spd.setProgress(getValue(MAKE_COLLECTION)); // 3. Copy files from the origin to the copied collections (except special collection files ending with ~). // As part of this we must rename origin.col to copy.col ///ystem.err.println("3. Copy origin."); ArrayList files = new ArrayList(); File collection_file = new File(Gatherer.c_man.getCollectionFilename()); File copied_dir; if (Gatherer.GS3) { copied_dir = new File(Utility.getCollectionDir(Configuration.gsdl3_path, Configuration.site_name, name)); } else { copied_dir = new File(Utility.getCollectionDir(Configuration.gsdl_path, name)); } files.add(collection_file.getParentFile()); while(files.size() > 0) { File file = (File) files.get(0); files.remove(0); if(file.isDirectory()) { File children[] = file.listFiles(); for(int i = 0; i < children.length; i++) { files.add(children[i]); } children = null; } else { // Rename origin.col file. if(file.equals(collection_file)) { File copied_file = new File(copied_dir, name + ".col"); copy(collection_file, copied_file); copied_file = null; } // Exclude *~ files from certain locations and lock.tmp file. else if(!file.getName().endsWith("~") && !file.getName().equals(CollectionManager.LOCK_FILE)) { StringTokenizer origin = new StringTokenizer(file.getAbsolutePath(), File.separator); StringTokenizer destin = new StringTokenizer(copied_dir.getAbsolutePath(), File.separator); while(destin.hasMoreTokens()) { origin.nextToken(); destin.nextToken(); } File copied_file = new File(copied_dir.getAbsolutePath()); while(origin.hasMoreTokens()) { copied_file = new File(copied_file, origin.nextToken()); } copy(file, copied_file); copied_file = null; origin = null; destin = null; } } file = null; } // spd.setProgress(getValue(COPY_COLLECTION)); // 4. Restore origin collection by undoing file copy actions and removing the ~ from the end of collection files. ///ystem.err.println("4. Restore origin."); // Gatherer.c_man.undo.undoAll(); ///ystem.err.println(" - UndoAll complete."); // Recurse collection tree restoring *~ files.clear(); // Should be empty anyway. files.add(collection_file.getParentFile()); while(files.size() > 0) { File file = (File) files.get(0); files.remove(0); if(file.isDirectory()) { File children[] = file.listFiles(); for(int i = 0; i < children.length; i++) { files.add(children[i]); } children = null; } else if(file.getName().endsWith("~")) { String filename = file.getAbsolutePath(); File original_file = new File(filename.substring(0, filename.length() - 1)); ///ystem.err.println("Renaming " + filename); if(!file.renameTo(original_file)) { DebugStream.println("Error in SaveCollectionTask.run(): FileRenameException"); } } } ///ystem.err.println(" - Restore *~ complete."); // spd.setProgress(getValue(RESTORE_COLLECTION)); // 5. Close the origin collection. ///ystem.err.println("5. Close origin."); collection.setSaved(true); Gatherer.c_man.closeCollection(); // spd.setProgress(getValue(CLOSE_COLLECTION)); // 6. Open the copied collection. ///ystem.err.println("6. Open copy."); Gatherer.c_man.loadCollection(copied_dir.getAbsolutePath() + File.separator + name + ".col"); // spd.setProgress(getValue(OPEN_COLLECTION)); copied_dir = null; } // spd.close(); // spd = null; tmp_loc = null; args = null; // Reset undo queue. // if(Gatherer.c_man.ready()) { // Gatherer.c_man.undo.clear(); // } Gatherer.g_man.wait(false); // Now we are finished action any necessary action. if(import_after) { Gatherer.c_man.importCollection(); } if(close_after) { Gatherer.c_man.closeCollection(); } ///ystem.err.println("Save Complete."); if(exit_after) { Gatherer.self.exit(); } } public void setImportAfter(boolean state) { import_after = true; } private void copy(File source, File destination) { ///ystem.err.println("Copy: " + source.getAbsolutePath()); ///ystem.err.println(" to: " + destination.getAbsolutePath()); try { destination.getParentFile().mkdirs(); FileInputStream f_in = new FileInputStream(source); FileOutputStream f_out = new FileOutputStream(destination); byte data[] = new byte[Utility.BUFFER_SIZE]; int data_size = 0; while((data_size = f_in.read(data, 0, Utility.BUFFER_SIZE)) != -1) { f_out.write(data, 0, data_size); } f_in.close(); f_out.close(); } catch (Exception exception) { DebugStream.printStackTrace(exception); } } private int getValue(int reference) { double multiplier; if(name == null) { multiplier = 1.0; } else { multiplier = 0.25; } switch(reference) { // Standard Save case COLLECTION_SAVED: return (int)((double)70 * multiplier); case COLLECTION_CFG_SAVED: case METADATA_SAVED: case METADATA_XML_SAVED: return (int)((double)10 * multiplier); // Save As case MAKE_COLLECTION: return 5; case COPY_COLLECTION: return 30; case RESTORE_COLLECTION: return 30; case CLOSE_COLLECTION: return 10; case OPEN_COLLECTION: return 10; } return 0; } }