/** *######################################################################### * * 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.msm; import java.io.*; import java.util.*; import org.greenstone.gatherer.Gatherer; import org.greenstone.gatherer.msm.MSMAdapter; import org.greenstone.gatherer.util.HashMap3D; import org.greenstone.gatherer.util.Utility; import org.w3c.dom.*; /** This class is essentially records what actions a user took when merging two metadata sets, so we can avoid having to get the user to repeat the proceedure. * @author John Thompson, Greenstone Digital Library, University of Waikato * @version 2.2 */ public class MSMProfiler extends MSMAdapter { /** The file the profile should be loaded from and saved to. */ private File profile_file = null; /** A mapping of known profile actions. */ private HashMap3D profiles = null; static final private String IGNORE = "\nIGNORE\n"; /** The constructor loads the previous profile for this collection if there is one. * @see org.greenstone.gatherer.collection.CollectionManager * @see org.greenstone.gatherer.msm.MetadataSetManager */ public MSMProfiler() { this.profile_file = new File(Gatherer.c_man.getCollectionMetadata(), "profile.xml"); this.profiles = new HashMap3D(); // Load an existing profile if there is one. if(profile_file.exists()) { Document document = Utility.parse(profile_file, false); if(document != null) { load(document); document = null; } } } /** Adds a new action mapping to the profile. Such a mapping records that for a certain collection (file) and metadata element a specific action must occur. The action is either a renaming to a new metadata element name, also provided, or an instruction to ignore this particular metadata element, is the target is null. * @param collection_file The aboslute path name to the collection where the metadata was sourced, as a String. * @param source A String containing the fully qualified name of the source metadata element. * @param target Another String which is either the fully qualified name of the target element, or null if this is actually an ignore action addition. */ public void addAction(String collection_file, String source, String target) { if(target == null) { target = IGNORE; } profiles.put(collection_file, source, target); } public void addSource(String collection_file) { profiles.put(collection_file, new HashMap()); } /** Determine if an action exists for the given collection and source. * @param collection_file The aboslute path name to the collection where the metadata was sourced, as a String. * @param source A String containing the fully qualified name of the source metadata element. * @return true if such an action exists, false otherwise. */ public boolean containsAction(String collection_file, String source) { return profiles.contains(collection_file, source); } public boolean containsSource(String collection_file) { return profiles.containsKey(collection_file); } /** Destructor to ensure that no memory leaks. */ public void destroy() { //save(); profiles.clear(); profile_file = null; profiles = null; } /** Method that is called whenever an element within a set is changed or modified, in which case we must modify the action profiles to suit. If an element was removed, remove all action profiles with this element as the target. If an elements name changes, update all matching targets to reflect new name. * @param event A MSMEvent containing details of the event that caused this message to be fired. */ public void elementChanged(MSMEvent event) { Gatherer.println("Element changed: " + event); String new_name = null; String old_name = event.getValue(); ElementWrapper element = event.getElement(); boolean delete = false; boolean rename = false; // First we check if the element has been removed. if(element == null) { delete = true; } // Next we determine if its name has changed else if(!(new_name = element.toString()).equals(old_name)) { rename = true; } // Perform any action we need to. if(delete || rename) { Iterator iterator_value_one = profiles.values().iterator(); while(iterator_value_one.hasNext()) { HashMap map = (HashMap) iterator_value_one.next(); Iterator iterator_key_two = map.keySet().iterator(); while(iterator_key_two.hasNext()) { String key_two = (String) iterator_key_two.next(); String value = (String) map.get(key_two); if(value.equals(old_name)) { if(delete) { map.remove(key_two); } else { map.put(key_two, new_name); } } key_two = null; value = null; } map = null; iterator_key_two = null; } iterator_value_one = null; } // Otherwise nothing for us to do (must be an add, or possibly a move if I can ever get round to the editor). element = null; old_name = null; new_name = null; } /** Search the profilerer for any previous actions regarding the indicated collection and metadata element. * @param collection_file The absolute path name to the collection where the metadata was sourced, as a String. * @param source A String containing the fully qualified name of the source metadata element. * @return The fully qualified name of the target metadata element, as a String, or null if we are to ignore this metadata. Note that the target elements name may be exactly the source elements one. */ public String getAction(String collection_file, String source) { ///atherer.println("Get action."); String result = (String) profiles.get(collection_file, source); if(result.equals(IGNORE)) { result = null; } return result; } public HashMap getActions(String collection_file) { return (HashMap) profiles.get(collection_file); } public ArrayList getCollections() { return new ArrayList(profiles.keySet()); } public ArrayList getSources(String collection_file) { ArrayList result = new ArrayList(); HashMap map = (HashMap) profiles.get(collection_file); if(map != null) { result.addAll(map.keySet()); } return result; } public void removeProfile(String collection_file) { profiles.remove(collection_file); } public void removeAction(String collection_file, String source) { HashMap map = (HashMap) profiles.get(collection_file); if(map != null) { map.remove(source); } } /** Save the profile document. */ public void save() { // While we're at it save the profiles. try { // Create backup. if(profile_file.exists()) { File backup = new File(profile_file.getAbsolutePath() + "~"); backup.deleteOnExit(); if(!profile_file.renameTo(backup)) { Gatherer.println("Error in MSMProfiler.save(): FileRenamedException"); } backup = null; } // read in the default profile file - has all the dtd in it Document document = Utility.parse(Utility.PROFILE_TEMPLATE, true); if(document == null) { Gatherer.println("Error in MSMProfiler.save(): couldn't find and parse the profile template file!"); return; } // Add the current profile info into the document Element profile_elem = document.getDocumentElement(); Iterator iterator_key_one = profiles.keySet().iterator(); while(iterator_key_one.hasNext()) { String key_one = (String) iterator_key_one.next(); HashMap map = (HashMap) profiles.get(key_one); Iterator iterator_key_two = map.keySet().iterator(); while(iterator_key_two.hasNext()) { String key_two = (String) iterator_key_two.next(); String value = (String) map.get(key_two); Element action = document.createElement("Action"); profile_elem.appendChild(action); action.setAttribute("collection", key_one); action.setAttribute("source", key_two); action.setAttribute("target", value); key_two = null; value = null; } key_one = null; map = null; iterator_key_two = null; } iterator_key_one = null; // Now write it to file. Utility.export(document, profile_file); } catch (Exception error) { Gatherer.printStackTrace(error); } } /** Reload the mapping information stored in this document. * @param document The Document to parse. */ private void load(Document document) { Element root = document.getDocumentElement(); NodeList actions = root.getElementsByTagName("Action"); for(int i = 0; i < actions.getLength(); i++) { Element action = (Element) actions.item(i); String collection = action.getAttribute("collection"); String source = action.getAttribute("source"); String target = action.getAttribute("target"); if(collection.length() > 0 && source.length() > 0) { if(target.length() == 0) { target = null; } profiles.put(collection, source, target); } action = null; collection = null; source = null; target = null; } root = null; actions = null; } }