Changeset 14037


Ignore:
Timestamp:
2007-05-03T08:49:31+12:00 (17 years ago)
Author:
xiao
Message:

Add a set of methods to read collectionConfig.xml into the internal DOM tree used by gli (the doXXX() methods), and convert the internal DOM tree back into collectionConfig.xml (the convertXXX() methods) and save to disk if any change has been made in gli by the user.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/gli/src/org/greenstone/gatherer/cdm/CollectionConfiguration.java

    r13592 r14037  
    4646import org.greenstone.gatherer.util.StaticStrings;
    4747import org.greenstone.gatherer.util.XMLTools;
     48import org.greenstone.gatherer.util.Utility;
    4849import org.w3c.dom.*;
    4950
     
    5253 * @version 2.3d
    5354 */
    54 public class CollectionConfiguration
    55 {
     55public class CollectionConfiguration {
    5656    static final private String ENCODING = "UTF-8";
    5757    static final private String NEWLINE_ELEMENT = "NewLine";
    58 
     58   
    5959    static private Document document;
    6060    static private StringBuffer saved_collect_cfg_string_buffer = null;
    61 
    62 
    63     static public Element createElement(String element_name)
    64     {
    65     return document.createElement(element_name);
    66     }
    67 
    68 
     61   
     62   
     63    static public Element createElement (String element_name) {
     64        return document.createElement (element_name);
     65    }
     66   
     67   
    6968    /** Find the best insertion position for the given DOM Element. This should try to match command tag, and if found should then try to group by name or type (eg CollectionMeta), or append to end is no such grouping exists (eg Plugins). Failing a command match it will check against the command order for the best insertion location.
    7069     * @param target_element the command Element to be inserted
    7170     * @return the Element which the given command should be inserted before, or null to append to end of list
    7271     */
    73     static public Node findInsertionPoint(Element target_element) {
    74     ///ystem.err.println("Find insertion point: " + target_element.getNodeName());
    75     String target_element_name = target_element.getNodeName();
    76     Element document_element = document.getDocumentElement();
    77     // Try to find commands with the same tag.
    78     NodeList matching_elements = document_element.getElementsByTagName(target_element_name);
    79     // If we found matching elements, then we have our most likely insertion location, so check within for groupings
    80     if(matching_elements.getLength() != 0) {
    81         ///ystem.err.println("Found matching elements.");
    82         // Only CollectionMeta are grouped.
    83         if(target_element_name.equals(StaticStrings.COLLECTIONMETADATA_ELEMENT)) {
    84         ///ystem.err.println("Dealing with collection metadata");
    85         // Special case: CollectionMeta can be added at either the start or end of a collection configuration file. However the start position is reserved for special metadata, so if no non-special metadata can be found we must append to the end.
    86         // So if the command to be added is special add it immediately after any other special command
    87         if(target_element.getAttribute(StaticStrings.SPECIAL_ATTRIBUTE).equals(StaticStrings.TRUE_STR)) {
    88             int index = 0;
    89             Element matched_element = (Element) matching_elements.item(index);
    90             Element sibling_element = (Element) matched_element.getNextSibling();
    91             while(sibling_element.getAttribute(StaticStrings.SPECIAL_ATTRIBUTE).equals(StaticStrings.TRUE_STR)) {
    92             index++;
    93             matched_element = (Element) matching_elements.item(index);
    94             sibling_element = (Element) matched_element.getNextSibling();
    95             }
    96             if(sibling_element.getNodeName().equals(NEWLINE_ELEMENT)) {
    97             Element newline_element = document.createElement(NEWLINE_ELEMENT);
    98             document_element.insertBefore(newline_element, sibling_element);
    99             }
    100             return sibling_element;
    101         }
    102         // Otherwise try to find a matching 'name' and add after the last one in that group.
    103         else {
    104             int index = 0;
    105             target_element_name = target_element.getAttribute(StaticStrings.NAME_ATTRIBUTE);
    106             boolean found = false;
    107             // Skip all of the special metadata
    108             Element matched_element = (Element) matching_elements.item(index);
    109             while(matched_element.getAttribute(StaticStrings.SPECIAL_ATTRIBUTE).equals(StaticStrings.TRUE_STR)) {
    110             index++;
    111             matched_element = (Element) matching_elements.item(index);
    112             }
    113             // Begin search
    114             while(!found && matched_element != null) {
    115             if(matched_element.getAttribute(StaticStrings.NAME_ATTRIBUTE).equals(target_element_name)) {
    116                 found = true;
    117             }
    118             else {
    119                 index++;
    120                 matched_element = (Element) matching_elements.item(index);
    121             }
    122             }
    123             // If we found a match, we need to continue checking until we find the last name match.
    124             if(found) {
    125             index++;
    126             Element previous_sibling = matched_element;
    127             Element sibling_element = (Element) matching_elements.item(index);
    128             while(sibling_element != null && sibling_element.getAttribute(StaticStrings.NAME_ATTRIBUTE).equals(target_element_name)) {
    129                 previous_sibling = sibling_element;
    130                 index++;
    131                 sibling_element = (Element) matching_elements.item(index);
    132             }
    133             // Previous sibling now holds the command immediately before where we want to add, so find its next sibling and add to that. In this one case we can ignore new lines!
    134             return previous_sibling.getNextSibling();
    135             }
    136             // If not found we just add after last metadata element
    137             else {
    138             Element last_element = (Element) matching_elements.item(matching_elements.getLength() - 1);
    139             return last_element.getNextSibling();
    140             }
    141         }
    142 
    143         }
    144         else {
    145         ///ystem.err.println("Not dealing with collection meta.");
    146         Element matched_element = (Element) matching_elements.item(matching_elements.getLength() - 1);
    147         // One final quick test. If the matched element is immediately followed by a NewLine command, then we insert another NewLine after the matched command, then return the NewLine instead (thus the about to be inserted command will be placed between the two NewLines)
    148         Node sibling_element = matched_element.getNextSibling();
    149         if(sibling_element != null && sibling_element.getNodeName().equals(NEWLINE_ELEMENT)) {
    150             Element newline_element = document.createElement(NEWLINE_ELEMENT);
    151             document_element.insertBefore(newline_element, sibling_element);
    152         }
    153         return sibling_element; // Note that this may be null
    154         }
    155     }
    156     ///ystem.err.println("No matching elements found.");
    157     // Locate where this command is in the ordering
    158     int command_index = -1;
    159     for(int i = 0; command_index == -1 && i < COMMAND_ORDER.length; i++) {
    160         if(COMMAND_ORDER[i].equals(target_element_name)) {
    161         command_index = i;
    162         }
    163     }
    164     ///ystem.err.println("Command index is: " + command_index);
    165     // Now move forward, checking for existing elements in each of the preceeding command orders.
    166     int preceeding_index = command_index - 1;
    167     ///ystem.err.println("Searching before the target command.");
    168     while(preceeding_index >= 0) {
    169         matching_elements = document_element.getElementsByTagName(COMMAND_ORDER[preceeding_index]);
    170         // If we've found a match
    171         if(matching_elements.getLength() > 0) {
    172         // We add after the last element
    173         Element matched_element = (Element) matching_elements.item(matching_elements.getLength() - 1);
    174         // One final quick test. If the matched element is immediately followed by a NewLine command, then we insert another NewLine after the matched command, then return the NewLine instead (thus the about to be inserted command will be placed between the two NewLines)
    175         Node sibling_element = matched_element.getNextSibling();
    176         if(sibling_element != null && sibling_element.getNodeName().equals(NEWLINE_ELEMENT)) {
    177             Element newline_element = document.createElement(NEWLINE_ELEMENT);
    178             document_element.insertBefore(newline_element, sibling_element);
    179         }
    180         return sibling_element; // Note that this may be null
    181         }
    182         preceeding_index--;
    183     }
    184     // If all that fails, we now move backwards through the commands
    185     int susceeding_index = command_index + 1;
    186     ///ystem.err.println("Searching after the target command.");
    187     while(susceeding_index < COMMAND_ORDER.length) {
    188         matching_elements = document_element.getElementsByTagName(COMMAND_ORDER[susceeding_index]);
    189         // If we've found a match
    190         if(matching_elements.getLength() > 0) {
    191         // We add before the first element
    192         Element matched_element = (Element) matching_elements.item(0);
    193         // One final quick test. If the matched element is immediately preceeded by a NewLine command, then we insert another NewLine before the matched command, then return this new NewLine instead (thus the about to be inserted command will be placed between the two NewLines)
    194         Node sibling_element = matched_element.getPreviousSibling();
    195         if(sibling_element != null && sibling_element.getNodeName().equals(NEWLINE_ELEMENT)) {
    196             Element newline_element = document.createElement(NEWLINE_ELEMENT);
    197             document_element.insertBefore(newline_element, sibling_element);
    198         }
    199         return sibling_element; // Note that this may be null
    200         }
    201         susceeding_index++;
    202     }
    203     // Well. Apparently there are no other commands in this collection configuration. So append away...
    204     return null;
    205     }
    206 
    207 
    208     static public NodeList getElementsByTagName(String element_name)
    209     {
    210     return document.getDocumentElement().getElementsByTagName(element_name);
    211     }
    212 
    213 
    214     static public String toString(Element command_element, boolean show_extracted_namespace) {
    215     String command_element_name = command_element.getNodeName();
    216     if(command_element_name.equals(StaticStrings.CLASSIFY_ELEMENT)) {
    217         return classifyToString(command_element, show_extracted_namespace);
    218     }
    219     else if(command_element_name.equals(StaticStrings.FORMAT_ELEMENT)) {
    220         return formatToString(command_element, show_extracted_namespace);
    221     }
    222     else if(command_element_name.equals(StaticStrings.INDEXES_ELEMENT)) {
    223         return indexesToString(command_element, show_extracted_namespace);
    224     }
    225     else if(command_element_name.equals(StaticStrings.INDEX_DEFAULT_ELEMENT)) {
    226         return indexDefaultToString(command_element, show_extracted_namespace);
    227     }
    228     else if(command_element_name.equals(StaticStrings.LANGUAGES_ELEMENT)) {
    229         return languagesToString(command_element);
    230     }
    231     else if(command_element_name.equals(StaticStrings.LANGUAGE_DEFAULT_ELEMENT)) {
    232         return languageDefaultToString(command_element);
    233     }
    234     else if (command_element_name.equals(StaticStrings.LANGUAGE_METADATA_ELEMENT)) {
    235         return languageMetadataToString(command_element, show_extracted_namespace);
    236     }
    237     else if(command_element_name.equals(StaticStrings.INDEXOPTIONS_ELEMENT)) {
    238         return indexOptionsToString(command_element);
    239     }
    240     else if(command_element_name.equals(StaticStrings.INDEXOPTION_DEFAULT_ELEMENT)) {
    241         return indexOptionDefaultToString(command_element);
    242     }
    243     else if(command_element_name.equals(StaticStrings.COLLECTIONMETADATA_ELEMENT)) {
    244         return metadataToString(command_element, show_extracted_namespace);
    245     }
    246     else if(command_element_name.equals(StaticStrings.COLLECTIONMETADATA_CREATOR_ELEMENT)) {
    247         return metadataToString(command_element, show_extracted_namespace);
    248     }
    249     else if(command_element_name.equals(StaticStrings.COLLECTIONMETADATA_MAINTAINER_ELEMENT)) {
    250         return metadataToString(command_element, show_extracted_namespace);
    251     }
    252     else if(command_element_name.equals(StaticStrings.COLLECTIONMETADATA_PUBLIC_ELEMENT)) {
    253         return metadataToString(command_element, show_extracted_namespace);
    254     }
    255     else if (command_element_name.equals(StaticStrings.BUILDTYPE_ELEMENT)) {
    256         return metadataToString(command_element, show_extracted_namespace);
    257     }
    258     else if(command_element_name.equals(StaticStrings.PLUGIN_ELEMENT)) {
    259         return pluginToString(command_element, show_extracted_namespace);
    260     }
    261     else if(command_element_name.equals(StaticStrings.SUBCOLLECTION_ELEMENT)) {
    262         return subcollectionToString(command_element, show_extracted_namespace);
    263     }
    264     else if(command_element_name.equals(StaticStrings.SUBCOLLECTION_DEFAULT_INDEX_ELEMENT)) {
    265         return subcollectionDefaultIndexToString(command_element);
    266     }
    267     else if(command_element_name.equals(StaticStrings.SUBCOLLECTION_INDEXES_ELEMENT)) {
    268         return subcollectionIndexesToString(command_element);
    269     }
    270     else if(command_element_name.equals(StaticStrings.SUPERCOLLECTION_ELEMENT)) {
    271         return supercollectionToString(command_element);
    272     }
    273     else if(command_element_name.equals(StaticStrings.UNKNOWN_ELEMENT)) {
    274         return unknownToString(command_element);
    275     }
    276     return "";
    277     }
    278 
     72    static public Node findInsertionPoint (Element target_element) {
     73        ///ystem.err.println("Find insertion point: " + target_element.getNodeName());
     74        String target_element_name = target_element.getNodeName ();
     75        Element document_element = document.getDocumentElement ();
     76        // Try to find commands with the same tag.
     77        NodeList matching_elements = document_element.getElementsByTagName (target_element_name);
     78        // If we found matching elements, then we have our most likely insertion location, so check within for groupings
     79        if(matching_elements.getLength () != 0) {
     80            ///ystem.err.println("Found matching elements.");
     81            // Only CollectionMeta are grouped.
     82            if(target_element_name.equals (StaticStrings.COLLECTIONMETADATA_ELEMENT)) {
     83                ///ystem.err.println("Dealing with collection metadata");
     84                // Special case: CollectionMeta can be added at either the start or end of a collection configuration file. However the start position is reserved for special metadata, so if no non-special metadata can be found we must append to the end.
     85                // So if the command to be added is special add it immediately after any other special command
     86                if(target_element.getAttribute (StaticStrings.SPECIAL_ATTRIBUTE).equals (StaticStrings.TRUE_STR)) {
     87                    int index = 0;
     88                    Element matched_element = (Element) matching_elements.item (index);
     89                    Element sibling_element = (Element) matched_element.getNextSibling ();
     90                    while(sibling_element.getAttribute (StaticStrings.SPECIAL_ATTRIBUTE).equals (StaticStrings.TRUE_STR)) {
     91                        index++;
     92                        matched_element = (Element) matching_elements.item (index);
     93                        sibling_element = (Element) matched_element.getNextSibling ();
     94                    }
     95                    if(sibling_element.getNodeName ().equals (NEWLINE_ELEMENT)) {
     96                        Element newline_element = document.createElement (NEWLINE_ELEMENT);
     97                        document_element.insertBefore (newline_element, sibling_element);
     98                    }
     99                    return sibling_element;
     100                }
     101                // Otherwise try to find a matching 'name' and add after the last one in that group.
     102                else {
     103                    int index = 0;
     104                    target_element_name = target_element.getAttribute (StaticStrings.NAME_ATTRIBUTE);
     105                    boolean found = false;
     106                    // Skip all of the special metadata
     107                    Element matched_element = (Element) matching_elements.item (index);
     108                    while(matched_element.getAttribute (StaticStrings.SPECIAL_ATTRIBUTE).equals (StaticStrings.TRUE_STR)) {
     109                        index++;
     110                        matched_element = (Element) matching_elements.item (index);
     111                    }
     112                    // Begin search
     113                    while(!found && matched_element != null) {
     114                        if(matched_element.getAttribute (StaticStrings.NAME_ATTRIBUTE).equals (target_element_name)) {
     115                            found = true;
     116                        }
     117                        else {
     118                            index++;
     119                            matched_element = (Element) matching_elements.item (index);
     120                        }
     121                    }
     122                    // If we found a match, we need to continue checking until we find the last name match.
     123                    if(found) {
     124                        index++;
     125                        Element previous_sibling = matched_element;
     126                        Element sibling_element = (Element) matching_elements.item (index);
     127                        while(sibling_element != null && sibling_element.getAttribute (StaticStrings.NAME_ATTRIBUTE).equals (target_element_name)) {
     128                            previous_sibling = sibling_element;
     129                            index++;
     130                            sibling_element = (Element) matching_elements.item (index);
     131                        }
     132                        // Previous sibling now holds the command immediately before where we want to add, so find its next sibling and add to that. In this one case we can ignore new lines!
     133                        return previous_sibling.getNextSibling ();
     134                    }
     135                    // If not found we just add after last metadata element
     136                    else {
     137                        Element last_element = (Element) matching_elements.item (matching_elements.getLength () - 1);
     138                        return last_element.getNextSibling ();
     139                    }
     140                }
     141               
     142            }
     143            else {
     144                ///ystem.err.println("Not dealing with collection meta.");
     145                Element matched_element = (Element) matching_elements.item (matching_elements.getLength () - 1);
     146                // One final quick test. If the matched element is immediately followed by a NewLine command, then we insert another NewLine after the matched command, then return the NewLine instead (thus the about to be inserted command will be placed between the two NewLines)
     147                Node sibling_element = matched_element.getNextSibling ();
     148                if(sibling_element != null && sibling_element.getNodeName ().equals (NEWLINE_ELEMENT)) {
     149                    Element newline_element = document.createElement (NEWLINE_ELEMENT);
     150                    document_element.insertBefore (newline_element, sibling_element);
     151                }
     152                return sibling_element; // Note that this may be null
     153            }
     154        }
     155        ///ystem.err.println("No matching elements found.");
     156        // Locate where this command is in the ordering
     157        int command_index = -1;
     158        for(int i = 0; command_index == -1 && i < COMMAND_ORDER.length; i++) {
     159            if(COMMAND_ORDER[i].equals (target_element_name)) {
     160                command_index = i;
     161            }
     162        }
     163        ///ystem.err.println("Command index is: " + command_index);
     164        // Now move forward, checking for existing elements in each of the preceeding command orders.
     165        int preceeding_index = command_index - 1;
     166        ///ystem.err.println("Searching before the target command.");
     167        while(preceeding_index >= 0) {
     168            matching_elements = document_element.getElementsByTagName (COMMAND_ORDER[preceeding_index]);
     169            // If we've found a match
     170            if(matching_elements.getLength () > 0) {
     171                // We add after the last element
     172                Element matched_element = (Element) matching_elements.item (matching_elements.getLength () - 1);
     173                // One final quick test. If the matched element is immediately followed by a NewLine command, then we insert another NewLine after the matched command, then return the NewLine instead (thus the about to be inserted command will be placed between the two NewLines)
     174                Node sibling_element = matched_element.getNextSibling ();
     175                if(sibling_element != null && sibling_element.getNodeName ().equals (NEWLINE_ELEMENT)) {
     176                    Element newline_element = document.createElement (NEWLINE_ELEMENT);
     177                    document_element.insertBefore (newline_element, sibling_element);
     178                }
     179                return sibling_element; // Note that this may be null
     180            }
     181            preceeding_index--;
     182        }
     183        // If all that fails, we now move backwards through the commands
     184        int susceeding_index = command_index + 1;
     185        ///ystem.err.println("Searching after the target command.");
     186        while(susceeding_index < COMMAND_ORDER.length) {
     187            matching_elements = document_element.getElementsByTagName (COMMAND_ORDER[susceeding_index]);
     188            // If we've found a match
     189            if(matching_elements.getLength () > 0) {
     190                // We add before the first element
     191                Element matched_element = (Element) matching_elements.item (0);
     192                // One final quick test. If the matched element is immediately preceeded by a NewLine command, then we insert another NewLine before the matched command, then return this new NewLine instead (thus the about to be inserted command will be placed between the two NewLines)
     193                Node sibling_element = matched_element.getPreviousSibling ();
     194                if(sibling_element != null && sibling_element.getNodeName ().equals (NEWLINE_ELEMENT)) {
     195                    Element newline_element = document.createElement (NEWLINE_ELEMENT);
     196                    document_element.insertBefore (newline_element, sibling_element);
     197                }
     198                return sibling_element; // Note that this may be null
     199            }
     200            susceeding_index++;
     201        }
     202        // Well. Apparently there are no other commands in this collection configuration. So append away...
     203        return null;
     204    }
     205   
     206   
     207    static public NodeList getElementsByTagName (String element_name) {
     208        return document.getDocumentElement ().getElementsByTagName (element_name);
     209    }
     210   
     211   
     212    static public String toString (Element command_element, boolean show_extracted_namespace) {
     213        String command_element_name = command_element.getNodeName ();
     214        if(command_element_name.equals (StaticStrings.CLASSIFY_ELEMENT)) {
     215            return classifyToString (command_element, show_extracted_namespace);
     216        }
     217        else if(command_element_name.equals (StaticStrings.FORMAT_ELEMENT)) {
     218            return formatToString (command_element, show_extracted_namespace);
     219        }
     220        else if(command_element_name.equals (StaticStrings.INDEXES_ELEMENT)) {
     221            return indexesToString (command_element, show_extracted_namespace);
     222        }
     223        else if(command_element_name.equals (StaticStrings.INDEX_DEFAULT_ELEMENT)) {
     224            return indexDefaultToString (command_element, show_extracted_namespace);
     225        }
     226        else if(command_element_name.equals (StaticStrings.LANGUAGES_ELEMENT)) {
     227            return languagesToString (command_element);
     228        }
     229        else if(command_element_name.equals (StaticStrings.LANGUAGE_DEFAULT_ELEMENT)) {
     230            return languageDefaultToString (command_element);
     231        }
     232        else if (command_element_name.equals (StaticStrings.LANGUAGE_METADATA_ELEMENT)) {
     233            return languageMetadataToString (command_element, show_extracted_namespace);
     234        }
     235        else if(command_element_name.equals (StaticStrings.INDEXOPTIONS_ELEMENT)) {
     236            return indexOptionsToString (command_element);
     237        }
     238        else if(command_element_name.equals (StaticStrings.INDEXOPTION_DEFAULT_ELEMENT)) {
     239            return indexOptionDefaultToString (command_element);
     240        }
     241        else if(command_element_name.equals (StaticStrings.COLLECTIONMETADATA_ELEMENT)) {
     242            return metadataToString (command_element, show_extracted_namespace);
     243        }
     244        else if(command_element_name.equals (StaticStrings.COLLECTIONMETADATA_CREATOR_ELEMENT)) {
     245            return metadataToString (command_element, show_extracted_namespace);
     246        }
     247        else if(command_element_name.equals (StaticStrings.COLLECTIONMETADATA_MAINTAINER_ELEMENT)) {
     248            return metadataToString (command_element, show_extracted_namespace);
     249        }
     250        else if(command_element_name.equals (StaticStrings.COLLECTIONMETADATA_PUBLIC_ELEMENT)) {
     251            return metadataToString (command_element, show_extracted_namespace);
     252        }
     253        else if (command_element_name.equals (StaticStrings.BUILDTYPE_ELEMENT)) {
     254            return metadataToString (command_element, show_extracted_namespace);
     255        }
     256        else if(command_element_name.equals (StaticStrings.PLUGIN_ELEMENT)) {
     257            return pluginToString (command_element, show_extracted_namespace);
     258        }
     259        else if(command_element_name.equals (StaticStrings.SUBCOLLECTION_ELEMENT)) {
     260            return subcollectionToString (command_element, show_extracted_namespace);
     261        }
     262        else if(command_element_name.equals (StaticStrings.SUBCOLLECTION_DEFAULT_INDEX_ELEMENT)) {
     263            return subcollectionDefaultIndexToString (command_element);
     264        }
     265        else if(command_element_name.equals (StaticStrings.SUBCOLLECTION_INDEXES_ELEMENT)) {
     266            return subcollectionIndexesToString (command_element);
     267        }
     268        else if(command_element_name.equals (StaticStrings.SUPERCOLLECTION_ELEMENT)) {
     269            return supercollectionToString (command_element);
     270        }
     271        else if(command_element_name.equals (StaticStrings.UNKNOWN_ELEMENT)) {
     272            return unknownToString (command_element);
     273        }
     274        return "";
     275    }
     276   
    279277    /** Parses arguments from a tokenizer and returns a HashMap of mappings. The tricky bit here is that not all entries in the HashMap are name->value pairs, as some arguments are boolean and are turned on by their presence. Arguments are denoted by a '-' prefix.
    280278     * @param tokenizer a CommandTokenizer based on the unconsumed portion of a command string
    281279     * @return a HashMap containing the arguments parsed
    282280     */
    283     static public HashMap parseArguments(CommandTokenizer tokenizer) {
    284     HashMap arguments = new HashMap();
    285     String name = null;
    286     String value = null;
    287     while(tokenizer.hasMoreTokens() || name != null) {
    288         // First we retrieve a name if we need one.
    289         if(name == null) {
    290         name = tokenizer.nextToken();
    291         }
    292         // Now we attempt to retrieve a value
    293         if(tokenizer.hasMoreTokens()) {
    294         value = tokenizer.nextToken();
    295         // Test if the value is actually a name, and if so add the name by itself, then put value into name so that it is parsed correctly during the next loop.
    296         if(value.startsWith(StaticStrings.MINUS_CHARACTER)) {
    297             arguments.put(name, null);
    298             name = value;
    299         }
    300         // Otherwise we have a typical name->value pair ready to go
    301         else {
    302             arguments.put(name, value);
    303             name = null;
    304         }
    305         }
    306         // Otherwise its a binary flag
    307         else {
    308         arguments.put(name, null);
    309         name = null;
    310         }
    311     }
    312     return arguments;
    313     }
    314 
     281    static public HashMap parseArguments (CommandTokenizer tokenizer) {
     282        HashMap arguments = new HashMap ();
     283        String name = null;
     284        String value = null;
     285        while(tokenizer.hasMoreTokens () || name != null) {
     286            // First we retrieve a name if we need one.
     287            if(name == null) {
     288                name = tokenizer.nextToken ();
     289            }
     290            // Now we attempt to retrieve a value
     291            if(tokenizer.hasMoreTokens ()) {
     292                value = tokenizer.nextToken ();
     293                // Test if the value is actually a name, and if so add the name by itself, then put value into name so that it is parsed correctly during the next loop.
     294                if(value.startsWith (StaticStrings.MINUS_CHARACTER)) {
     295                    arguments.put (name, null);
     296                    name = value;
     297                }
     298                // Otherwise we have a typical name->value pair ready to go
     299                else {
     300                    arguments.put (name, value);
     301                    name = null;
     302                }
     303            }
     304            // Otherwise its a binary flag
     305            else {
     306                arguments.put (name, null);
     307                name = null;
     308            }
     309        }
     310        return arguments;
     311    }
     312   
    315313    /** Gives the preferred ordering of commands */
    316     static final private String[] COMMAND_ORDER = {StaticStrings.COLLECTIONMETADATA_CREATOR_ELEMENT, StaticStrings.COLLECTIONMETADATA_MAINTAINER_ELEMENT, StaticStrings.COLLECTIONMETADATA_PUBLIC_ELEMENT, StaticStrings.BUILDTYPE_ELEMENT, StaticStrings.PLUGIN_ELEMENT, StaticStrings.INDEXES_ELEMENT, StaticStrings.INDEX_DEFAULT_ELEMENT, StaticStrings.INDEXOPTIONS_ELEMENT, StaticStrings.INDEXOPTION_DEFAULT_ELEMENT, StaticStrings.LANGUAGES_ELEMENT, StaticStrings.LANGUAGE_DEFAULT_ELEMENT, StaticStrings.LANGUAGE_METADATA_ELEMENT, StaticStrings.SUBCOLLECTION_ELEMENT, StaticStrings.SUBCOLLECTION_INDEXES_ELEMENT, StaticStrings.SUBCOLLECTION_DEFAULT_INDEX_ELEMENT, StaticStrings.SUPERCOLLECTION_ELEMENT, StaticStrings.CLASSIFY_ELEMENT, StaticStrings.FORMAT_ELEMENT, StaticStrings.COLLECTIONMETADATA_ELEMENT};
    317 
     314    static final private String[] COMMAND_ORDER =
     315    {StaticStrings.COLLECTIONMETADATA_CREATOR_ELEMENT, StaticStrings.COLLECTIONMETADATA_MAINTAINER_ELEMENT, StaticStrings.COLLECTIONMETADATA_PUBLIC_ELEMENT, StaticStrings.BUILDTYPE_ELEMENT, StaticStrings.PLUGIN_ELEMENT, StaticStrings.INDEXES_ELEMENT, StaticStrings.INDEX_DEFAULT_ELEMENT, StaticStrings.INDEXOPTIONS_ELEMENT, StaticStrings.INDEXOPTION_DEFAULT_ELEMENT, StaticStrings.LANGUAGES_ELEMENT, StaticStrings.LANGUAGE_DEFAULT_ELEMENT, StaticStrings.LANGUAGE_METADATA_ELEMENT, StaticStrings.SUBCOLLECTION_ELEMENT, StaticStrings.SUBCOLLECTION_INDEXES_ELEMENT, StaticStrings.SUBCOLLECTION_DEFAULT_INDEX_ELEMENT, StaticStrings.SUPERCOLLECTION_ELEMENT, StaticStrings.CLASSIFY_ELEMENT, StaticStrings.FORMAT_ELEMENT, StaticStrings.COLLECTIONMETADATA_ELEMENT};
     316   
    318317    /** ************************** Public Data Members ***************************/
    319 
     318   
    320319    /** ************************** Private Data Members ***************************/
    321320   
    322321    private File collect_cfg_file;
    323 
     322   
    324323    /** ************************** Public Methods ***************************/
    325 
    326     public CollectionConfiguration(File collect_cfg_file)
    327     {
    328     this.collect_cfg_file = collect_cfg_file;
    329     // parse the XML template
    330     document = XMLTools.parseXMLFile("xml/CollectionConfig.xml", true);
    331     parse(collect_cfg_file);
    332    
    333     }
    334 
     324   
     325   
    335326    /** This debug facility shows the currently loaded collect.cfg or CollectConfig.xml file as a DOM tree. */
    336     public void display() {
    337     JDialog dialog = new JDialog(Gatherer.g_man, "Collection Configuration", false);
    338     dialog.setSize(400,400);
    339     JPanel content_pane = (JPanel) dialog.getContentPane();
    340     final DOMTree tree = new DOMTree(document);
    341     JButton refresh_button = new GLIButton("Refresh Tree");
    342     refresh_button.addActionListener(new ActionListener() {
    343         public void actionPerformed(ActionEvent event) {
    344             tree.setDocument(document);
    345         }
    346         });
    347     content_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
    348     content_pane.setLayout(new BorderLayout());
    349     content_pane.add(new JScrollPane(tree), BorderLayout.CENTER);
    350     content_pane.add(refresh_button, BorderLayout.SOUTH);
    351     dialog.setVisible(true);
    352     }
    353 
    354 
    355     public Element getCreator() {
    356     Element element = getOrCreateElementByTagName(StaticStrings.COLLECTIONMETADATA_CREATOR_ELEMENT, null, null);
    357     element.setAttribute(StaticStrings.NAME_ATTRIBUTE, StaticStrings.COLLECTIONMETADATA_CREATOR_STR);
    358     element.setAttribute(StaticStrings.SPECIAL_ATTRIBUTE, StaticStrings.TRUE_STR);
    359     return element;
    360     }
    361 
    362     public Element getDocumentElement() {
    363     return document.getDocumentElement();
    364     }
    365 
    366     public File getFile() {
    367     return collect_cfg_file;
    368     }
    369 
     327    public void display () {
     328        JDialog dialog = new JDialog (Gatherer.g_man, "Collection Configuration", false);
     329        dialog.setSize (400,400);
     330        JPanel content_pane = (JPanel) dialog.getContentPane ();
     331        final DOMTree tree = new DOMTree (document);
     332        JButton refresh_button = new GLIButton ("Refresh Tree");
     333        refresh_button.addActionListener (new ActionListener () {
     334            public void actionPerformed (ActionEvent event) {
     335                tree.setDocument (document);
     336            }
     337        });
     338        content_pane.setBorder (BorderFactory.createEmptyBorder (5,5,5,5));
     339        content_pane.setLayout (new BorderLayout ());
     340        content_pane.add (new JScrollPane (tree), BorderLayout.CENTER);
     341        content_pane.add (refresh_button, BorderLayout.SOUTH);
     342        dialog.setVisible (true);
     343    }
     344   
     345   
     346    public Element getCreator () {
     347        Element element = getOrCreateElementByTagName (StaticStrings.COLLECTIONMETADATA_CREATOR_ELEMENT, null, null);
     348        element.setAttribute (StaticStrings.NAME_ATTRIBUTE, StaticStrings.COLLECTIONMETADATA_CREATOR_STR);
     349        element.setAttribute (StaticStrings.SPECIAL_ATTRIBUTE, StaticStrings.TRUE_STR);
     350        return element;
     351    }
     352   
     353    public Element getDocumentElement () {
     354        return document.getDocumentElement ();
     355    }
     356   
     357    public File getFile () {
     358        return collect_cfg_file;
     359    }
     360   
    370361    /** Retrieve or create the languages Element. */
    371     public Element getLanguages() {
    372     return getOrCreateElementByTagName(StaticStrings.LANGUAGES_ELEMENT, null, null);
    373     }
    374 
    375     public Element getLanguageMetadata() {
    376     return getOrCreateElementByTagName(StaticStrings.LANGUAGE_METADATA_ELEMENT, null, null);
    377     }
    378    
    379     public Element getLevels() {
    380     return getOrCreateElementByTagName(StaticStrings.INDEXOPTIONS_ELEMENT, StaticStrings.NAME_ATTRIBUTE, StaticStrings.LEVELS_STR);
    381      }
    382 
    383     public Element getLevelDefault() {
    384     return getOrCreateElementByTagName(StaticStrings.INDEXOPTION_DEFAULT_ELEMENT, StaticStrings.NAME_ATTRIBUTE, StaticStrings.LEVEL_DEFAULT_STR);
    385      }
    386    
    387     public Element getStemOptions() {
    388     return getOrCreateElementByTagName(StaticStrings.INDEXOPTIONS_ELEMENT, StaticStrings.NAME_ATTRIBUTE, StaticStrings.STEMOPTIONS_STR);
    389      }
    390    
    391    
    392     public Element getMaintainer() {
    393     Element element = getOrCreateElementByTagName(StaticStrings.COLLECTIONMETADATA_MAINTAINER_ELEMENT, null, null);
    394     element.setAttribute(StaticStrings.NAME_ATTRIBUTE, StaticStrings.COLLECTIONMETADATA_MAINTAINER_STR);
    395     element.setAttribute(StaticStrings.SPECIAL_ATTRIBUTE, StaticStrings.TRUE_STR);
    396     return element;
    397     }
    398 
     362    public Element getLanguages () {
     363        return getOrCreateElementByTagName (StaticStrings.LANGUAGES_ELEMENT, null, null);
     364    }
     365   
     366    public Element getLanguageMetadata () {
     367        return getOrCreateElementByTagName (StaticStrings.LANGUAGE_METADATA_ELEMENT, null, null);
     368    }
     369   
     370    public Element getLevels () {
     371        return getOrCreateElementByTagName (StaticStrings.INDEXOPTIONS_ELEMENT, StaticStrings.NAME_ATTRIBUTE, StaticStrings.LEVELS_STR);
     372    }
     373   
     374    public Element getLevelDefault () {
     375        return getOrCreateElementByTagName (StaticStrings.INDEXOPTION_DEFAULT_ELEMENT, StaticStrings.NAME_ATTRIBUTE, StaticStrings.LEVEL_DEFAULT_STR);
     376    }
     377   
     378    public Element getStemOptions () {
     379        return getOrCreateElementByTagName (StaticStrings.INDEXOPTIONS_ELEMENT, StaticStrings.NAME_ATTRIBUTE, StaticStrings.STEMOPTIONS_STR);
     380    }
     381   
     382   
     383    public Element getMaintainer () {
     384        Element element = getOrCreateElementByTagName (StaticStrings.COLLECTIONMETADATA_MAINTAINER_ELEMENT, null, null);
     385        element.setAttribute (StaticStrings.NAME_ATTRIBUTE, StaticStrings.COLLECTIONMETADATA_MAINTAINER_STR);
     386        element.setAttribute (StaticStrings.SPECIAL_ATTRIBUTE, StaticStrings.TRUE_STR);
     387        return element;
     388    }
     389   
    399390    /** Retrieve or create the indexes Element. Note that this method behaves differently from the other getBlah methods, in that it also has to keep in mind that indexes come in two flavours, MG and MGPP. */
    400     public Element getMGIndexes() {
    401     return getOrCreateElementByTagName(StaticStrings.INDEXES_ELEMENT, StaticStrings.MGPP_ATTRIBUTE, StaticStrings.FALSE_STR);
    402     }
    403 
    404     public Element getMGPPIndexes() {
    405     return getOrCreateElementByTagName(StaticStrings.INDEXES_ELEMENT, StaticStrings.MGPP_ATTRIBUTE, StaticStrings.TRUE_STR);
    406     }
    407 
    408     public Element getPublic() {
    409     Element element = getOrCreateElementByTagName(StaticStrings.COLLECTIONMETADATA_PUBLIC_ELEMENT, null, null);
    410     element.setAttribute(StaticStrings.NAME_ATTRIBUTE, StaticStrings.COLLECTIONMETADATA_PUBLIC_STR);
    411     element.setAttribute(StaticStrings.SPECIAL_ATTRIBUTE, StaticStrings.TRUE_STR);
    412     return element;
    413     }
    414 
    415     public Element getBuildType() {
    416     Element element = getOrCreateElementByTagName(StaticStrings.BUILDTYPE_ELEMENT, null, null);
    417     element.setAttribute(StaticStrings.NAME_ATTRIBUTE, StaticStrings.BUILDTYPE_STR);
    418     element.setAttribute(StaticStrings.SPECIAL_ATTRIBUTE, StaticStrings.TRUE_STR);
    419     return element;
    420 
    421     }
    422 
     391    public Element getMGIndexes () {
     392        return getOrCreateElementByTagName (StaticStrings.INDEXES_ELEMENT, StaticStrings.MGPP_ATTRIBUTE, StaticStrings.FALSE_STR);
     393    }
     394   
     395    public Element getMGPPIndexes () {
     396        return getOrCreateElementByTagName (StaticStrings.INDEXES_ELEMENT, StaticStrings.MGPP_ATTRIBUTE, StaticStrings.TRUE_STR);
     397    }
     398   
     399    public Element getPublic () {
     400        Element element = getOrCreateElementByTagName (StaticStrings.COLLECTIONMETADATA_PUBLIC_ELEMENT, null, null);
     401        element.setAttribute (StaticStrings.NAME_ATTRIBUTE, StaticStrings.COLLECTIONMETADATA_PUBLIC_STR);
     402        element.setAttribute (StaticStrings.SPECIAL_ATTRIBUTE, StaticStrings.TRUE_STR);
     403        return element;
     404    }
     405   
     406    public Element getBuildType () {
     407        Element element = getOrCreateElementByTagName (StaticStrings.BUILDTYPE_ELEMENT, null, null);
     408        element.setAttribute (StaticStrings.NAME_ATTRIBUTE, StaticStrings.BUILDTYPE_STR);
     409        element.setAttribute (StaticStrings.SPECIAL_ATTRIBUTE, StaticStrings.TRUE_STR);
     410        return element;
     411       
     412    }
     413   
    423414    /** Retrieve or create the subindexes Element. */
    424     public Element getSubIndexes() {
    425     return getOrCreateElementByTagName(StaticStrings.SUBCOLLECTION_INDEXES_ELEMENT, null, null);
    426     }
    427 
     415    public Element getSubIndexes () {
     416        return getOrCreateElementByTagName (StaticStrings.SUBCOLLECTION_INDEXES_ELEMENT, null, null);
     417    }
     418   
    428419    /** Retrieve or create the supercollections Element. */
    429     public Element getSuperCollection() {
    430     return getOrCreateElementByTagName(StaticStrings.SUPERCOLLECTION_ELEMENT, null, null);
    431     }
    432 
    433     public boolean ready() {
    434     return document != null;
    435     }
    436 
    437 
    438     public void saveIfNecessary()
    439     {
    440     // Convert the collection configuration XML tree to the collect.cfg version
    441     StringBuffer collect_cfg_string_buffer = new StringBuffer();
    442     NodeList command_elements = document.getDocumentElement().getChildNodes();
    443     boolean just_wrote_blank_line = false;  // Prevent two or more blank lines in a row
    444     for (int i = 0; i < command_elements.getLength(); i++) {
    445         Node command_node = command_elements.item(i);
    446         if (!(command_node instanceof Element)) {
    447         // We're only interested in Elements
    448         continue;
    449         }
    450         Element command_element = (Element) command_node;
    451 
    452         // Handle NewLine elements (blank lines)
    453         if (command_element.getNodeName().equals(NEWLINE_ELEMENT) && !just_wrote_blank_line) {
    454         collect_cfg_string_buffer.append("\n");
    455         just_wrote_blank_line = true;
    456         }
    457 
    458         // Anything else we write to file, but only if it has been assigned, except for index and level commands
    459         // (which just get commented out if unassigned -- a side effect of MG & MGPP compatibility)
    460         else if (!command_element.getAttribute(StaticStrings.ASSIGNED_ATTRIBUTE).equals(StaticStrings.FALSE_STR) || command_element.getNodeName().equals(StaticStrings.INDEXES_ELEMENT) || command_element.getNodeName().equals(StaticStrings.INDEX_DEFAULT_ELEMENT) || command_element.getNodeName().equals(StaticStrings.INDEXOPTIONS_ELEMENT) || command_element.getNodeName().equals(StaticStrings.INDEXOPTION_DEFAULT_ELEMENT)) {
    461         String command;
    462         if (command_element.getNodeName().equals(StaticStrings.FORMAT_ELEMENT)) {
    463             // Format statements we write out with ex. still present
    464             command = toString(command_element, true);
    465         }
    466         else {
    467             command = toString(command_element, false);
    468         }
    469 
    470         if (command != null && command.length()> 0 ) {
    471             collect_cfg_string_buffer.append(command + "\n");
    472             just_wrote_blank_line = false;
    473         }
    474         }
    475     }
    476 
    477     String collect_cfg_string = collect_cfg_string_buffer.toString();
    478     String saved_collect_cfg_string = saved_collect_cfg_string_buffer.toString();
    479     if (collect_cfg_string.equals(saved_collect_cfg_string)) {
    480         DebugStream.println("Collect.cfg file hasn't changed so no save necessary...");
    481         return;
    482     }
    483 
    484     DebugStream.println("Collect.cfg file has changed, saving now...");
    485 
    486     // If we're using the Local Library we must release the collection before writing to the collect.cfg file
    487     String collection_name = CollectionManager.getLoadedCollectionName();
    488     boolean collection_released = false;
    489     if (Gatherer.c_man.built() && LocalLibraryServer.isRunning() == true) {
    490         // Release the collection
    491         LocalLibraryServer.releaseCollection(collection_name);
    492         collection_released = true;
    493     }
    494 
    495     // Make a backup of the collect.cfg file
    496     if (collect_cfg_file.exists()) {
    497         File original_file = new File(collect_cfg_file.getParentFile(), StaticStrings.COLLECT_CFG);
    498         File backup_file = new File(collect_cfg_file.getParentFile(), "collect.bak");
    499         if (backup_file.exists()) {
    500         backup_file.delete();
    501         }
    502         if (!original_file.renameTo(backup_file)) {
    503         System.err.println("Warning: can't rename collect.cfg to collect.bak.");
    504         }
    505     }
    506 
    507     try {       
    508         OutputStream ostream = new FileOutputStream(collect_cfg_file);
    509         Writer file_writer = new OutputStreamWriter(ostream, ENCODING);
    510         BufferedWriter buffered_writer = new BufferedWriter(file_writer);
    511         buffered_writer.write(collect_cfg_string);
    512         buffered_writer.close();
    513 
    514         saved_collect_cfg_string_buffer = collect_cfg_string_buffer;
    515 
    516         // If we're using a remote Greenstone server, upload the new collect.cfg file
    517         if (Gatherer.isGsdlRemote) {
    518         RemoteGreenstoneServer.uploadCollectionFile(collection_name, collect_cfg_file);
    519         }
    520     }
    521     catch (Exception exception) {
    522         DebugStream.println("Error in CollectionConfiguration.save(): " + exception);
    523         DebugStream.printStackTrace(exception);
    524     }
    525 
    526     // Now re-add the collection to the Local Library server
    527     if (collection_released) {
    528         LocalLibraryServer.addCollection(collection_name);
    529     }   
    530     }
    531 
    532 
     420    public Element getSuperCollection () {
     421        return getOrCreateElementByTagName (StaticStrings.SUPERCOLLECTION_ELEMENT, null, null);
     422    }
     423   
     424    public boolean ready () {
     425        return document != null;
     426    }
     427   
     428   
     429   
     430   
    533431    /** ************************** Private Methods ***************************/
    534 
    535     static private String classifyToString(Element command_element, boolean show_extracted_namespace)
    536     {
    537     StringBuffer text = new StringBuffer(StaticStrings.CLASSIFY_STR);
    538     text.append(StaticStrings.TAB_CHARACTER);
    539     text.append(command_element.getAttribute(StaticStrings.TYPE_ATTRIBUTE));
    540     NodeList option_elements = command_element.getElementsByTagName(StaticStrings.OPTION_ELEMENT);
    541     int option_elements_length = option_elements.getLength();
    542     for(int j = 0; j < option_elements_length; j++) {
    543         Element option_element = (Element) option_elements.item(j);
    544         if(option_element.getAttribute(StaticStrings.ASSIGNED_ATTRIBUTE).equals(StaticStrings.TRUE_STR)) {
    545         text.append(StaticStrings.SPACE_CHARACTER);
    546         text.append(StaticStrings.MINUS_CHARACTER);
    547         text.append(option_element.getAttribute(StaticStrings.NAME_ATTRIBUTE));
    548         String value_str = XMLTools.getValue(option_element);
    549 
    550         // Convert metadata element names to internal names, and remove extracted metadata namespaces
    551         if (value_str.length() > 0) {
    552             StringTokenizer string_tokenizer = new StringTokenizer(value_str, ",");
    553             StringBuffer value_buffer = new StringBuffer();
    554             while (string_tokenizer.hasMoreElements()) {
    555             String raw_token = (String) string_tokenizer.nextElement();
    556             String token = raw_token.trim();
    557             MetadataElement metadata_element = MetadataTools.getMetadataElementWithDisplayName(token);
    558             if (metadata_element != null) {
    559                 token = metadata_element.getFullName();
    560             }
    561 
    562             if (token.startsWith(StaticStrings.EXTRACTED_NAMESPACE)) {
    563                 token = token.substring(StaticStrings.EXTRACTED_NAMESPACE.length());
    564             }
    565             value_buffer.append(token);
    566             if (string_tokenizer.hasMoreElements()) {
    567                 value_buffer.append(",");
    568             }
    569             }
    570             value_str = value_buffer.toString();
    571         }
    572 
    573         text.append(StaticStrings.SPACE_CHARACTER);
    574         if (value_str.indexOf(StaticStrings.SPACE_CHARACTER) == -1) {
    575             text.append(value_str);
    576         }
    577         else {
    578             text.append(StaticStrings.SPEECH_CHARACTER);
    579             text.append(value_str);
    580             text.append(StaticStrings.SPEECH_CHARACTER);
    581         }
    582         value_str = null;
    583         }
    584         option_element = null;
    585     }
    586     option_elements = null;
    587     return text.toString();
    588     }
    589 
    590     static private String formatToString(Element command_element, boolean show_extracted_namespace) {
    591     StringBuffer text = new StringBuffer(StaticStrings.FORMAT_STR);
    592     text.append(StaticStrings.SPACE_CHARACTER);
    593     text.append(command_element.getAttribute(StaticStrings.NAME_ATTRIBUTE));
    594     text.append(StaticStrings.SPACE_CHARACTER);
    595     String value_str = command_element.getAttribute(StaticStrings.VALUE_ATTRIBUTE);
    596     if(value_str.length() != 0) {
    597         text.append(value_str);
    598     }
    599     else {
    600         // Remember to encode format string to Greenstone specification
    601         value_str = Codec.transform(XMLTools.getValue(command_element), Codec.DOM_TO_GREENSTONE);
    602         // Remove any references to a namespace for extracted metadata
    603         if (!show_extracted_namespace) {
    604         String match_string = "\\[" + MetadataSetManager.EXTRACTED_METADATA_NAMESPACE + "\\.";
    605         value_str = value_str.replaceAll(match_string, "[");
    606         }
    607 
    608         text.append(StaticStrings.SPEECH_CHARACTER);
    609         text.append(value_str);
    610         text.append(StaticStrings.SPEECH_CHARACTER);
    611     }
    612     value_str = null;
    613     return text.toString();
    614     }
    615 
     432   
     433    static private String classifyToString (Element command_element, boolean show_extracted_namespace) {
     434        StringBuffer text = new StringBuffer (StaticStrings.CLASSIFY_STR);
     435        text.append (StaticStrings.TAB_CHARACTER);
     436        text.append (command_element.getAttribute (StaticStrings.TYPE_ATTRIBUTE));
     437        NodeList option_elements = command_element.getElementsByTagName (StaticStrings.OPTION_ELEMENT);
     438        int option_elements_length = option_elements.getLength ();
     439        for(int j = 0; j < option_elements_length; j++) {
     440            Element option_element = (Element) option_elements.item (j);
     441            if(option_element.getAttribute (StaticStrings.ASSIGNED_ATTRIBUTE).equals (StaticStrings.TRUE_STR)) {
     442                text.append (StaticStrings.SPACE_CHARACTER);
     443                text.append (StaticStrings.MINUS_CHARACTER);
     444                text.append (option_element.getAttribute (StaticStrings.NAME_ATTRIBUTE));
     445                String value_str = XMLTools.getValue (option_element);
     446               
     447                // Convert metadata element names to internal names, and remove extracted metadata namespaces
     448                if (value_str.length () > 0) {
     449                    StringTokenizer string_tokenizer = new StringTokenizer (value_str, ",");
     450                    StringBuffer value_buffer = new StringBuffer ();
     451                    while (string_tokenizer.hasMoreElements ()) {
     452                        String raw_token = (String) string_tokenizer.nextElement ();
     453                        String token = raw_token.trim ();
     454                        MetadataElement metadata_element = MetadataTools.getMetadataElementWithDisplayName (token);
     455                        if (metadata_element != null) {
     456                            token = metadata_element.getFullName ();
     457                        }
     458                       
     459                        if (token.startsWith (StaticStrings.EXTRACTED_NAMESPACE)) {
     460                            token = token.substring (StaticStrings.EXTRACTED_NAMESPACE.length ());
     461                        }
     462                        value_buffer.append (token);
     463                        if (string_tokenizer.hasMoreElements ()) {
     464                            value_buffer.append (",");
     465                        }
     466                    }
     467                    value_str = value_buffer.toString ();
     468                }
     469               
     470                text.append (StaticStrings.SPACE_CHARACTER);
     471                if (value_str.indexOf (StaticStrings.SPACE_CHARACTER) == -1) {
     472                    text.append (value_str);
     473                }
     474                else {
     475                    text.append (StaticStrings.SPEECH_CHARACTER);
     476                    text.append (value_str);
     477                    text.append (StaticStrings.SPEECH_CHARACTER);
     478                }
     479                value_str = null;
     480            }
     481            option_element = null;
     482        }
     483        option_elements = null;
     484        return text.toString ();
     485    }
     486   
     487    static private String formatToString (Element command_element, boolean show_extracted_namespace) {
     488        StringBuffer text = new StringBuffer (StaticStrings.FORMAT_STR);
     489        text.append (StaticStrings.SPACE_CHARACTER);
     490        text.append (command_element.getAttribute (StaticStrings.NAME_ATTRIBUTE));
     491        text.append (StaticStrings.SPACE_CHARACTER);
     492        String value_str = command_element.getAttribute (StaticStrings.VALUE_ATTRIBUTE);
     493        if(value_str.length () != 0) {
     494            text.append (value_str);
     495        }
     496        else {
     497            // Remember to encode format string to Greenstone specification
     498            value_str = Codec.transform (XMLTools.getValue (command_element), Codec.DOM_TO_GREENSTONE);
     499            // Remove any references to a namespace for extracted metadata
     500            if (!show_extracted_namespace) {
     501                String match_string = "\\[" + MetadataSetManager.EXTRACTED_METADATA_NAMESPACE + "\\.";
     502                value_str = value_str.replaceAll (match_string, "[");
     503            }
     504           
     505            text.append (StaticStrings.SPEECH_CHARACTER);
     506            text.append (value_str);
     507            text.append (StaticStrings.SPEECH_CHARACTER);
     508        }
     509        value_str = null;
     510        return text.toString ();
     511    }
     512   
    616513    /** Retrieve or create the indexes Element. */
    617     static private Element getOrCreateElementByTagName(String name, String conditional_attribute, String required_value) {
    618     Element document_element = document.getDocumentElement();
    619     NodeList elements = document_element.getElementsByTagName(name);
    620     int elements_length = elements.getLength();
    621     if(elements_length > 0) {
    622         if(conditional_attribute == null) {
    623         document_element = null;
    624         return (Element) elements.item(0);
    625         }
    626         else {
    627         for(int i = 0; i < elements_length; i++) {
    628             Element element = (Element) elements.item(i);
    629             if(element.getAttribute(conditional_attribute).equals(required_value)) {
    630             document_element = null;
    631             return element;
    632             }
    633             element = null;
    634         }
    635         }
    636     }
    637     // Create the element
    638     Element element = document.createElement(name);
    639     // If there was a property set it
    640     if(conditional_attribute != null) {
    641         element.setAttribute(conditional_attribute, required_value);
    642     }
    643     Node target_node = findInsertionPoint(element);
    644     if(target_node != null) {
    645         document_element.insertBefore(element, target_node);
    646     }
    647     else {
    648         document_element.appendChild(element);
    649     }
    650     document_element = null;
    651     return element;
    652     }
    653 
    654     static private String indexesToString(Element command_element, boolean show_extracted_namespace) {
    655     boolean comment_only = false;
    656     StringBuffer text = new StringBuffer("");
    657     if(command_element.getAttribute(StaticStrings.ASSIGNED_ATTRIBUTE).equals(StaticStrings.FALSE_STR)) {
    658         text.append("#");
    659         comment_only = true;
    660     }
    661     text.append(StaticStrings.INDEX_STR);
    662     text.append(StaticStrings.TAB_CHARACTER);
    663     if(!comment_only) {
    664         text.append(StaticStrings.TAB_CHARACTER);
    665     }
    666     NodeList index_elements = command_element.getElementsByTagName(StaticStrings.INDEX_ELEMENT);
    667     if (index_elements.getLength() == 0) { // no indexes
    668         return "";
    669     }
    670     // For each index, write its level, a colon, then concatenate its child content elements into a single comma separated list
    671     int index_elements_length = index_elements.getLength();
    672     for(int j = 0; j < index_elements_length; j++) {
    673         Element index_element = (Element) index_elements.item(j);
    674         String level_str = index_element.getAttribute(StaticStrings.LEVEL_ATTRIBUTE);
    675         if(level_str.length() > 0) {
    676         text.append(level_str);
    677         text.append(StaticStrings.COLON_CHARACTER);
    678         }
    679         NodeList content_elements = index_element.getElementsByTagName(StaticStrings.CONTENT_ELEMENT);
    680         int content_elements_length = content_elements.getLength();
    681         // Don't output anything if no indexes are set
    682         if(content_elements_length == 0) {
    683         return null;
    684         }
    685         for(int k = 0; k < content_elements_length; k++) {
    686         Element content_element = (Element) content_elements.item(k);
    687         String name_str = content_element.getAttribute(StaticStrings.NAME_ATTRIBUTE);
    688         if(!show_extracted_namespace && name_str.startsWith(StaticStrings.EXTRACTED_NAMESPACE)) {
    689             name_str = name_str.substring(StaticStrings.EXTRACTED_NAMESPACE.length());
    690         }
    691         text.append(name_str);
    692         name_str = null;
    693         if(k < content_elements_length - 1) {
    694             text.append(StaticStrings.COMMA_CHARACTER);
    695         }
    696         content_element = null;
    697         }
    698         if(j < index_elements_length - 1) {
    699         text.append(StaticStrings.SPACE_CHARACTER);
    700         }
    701         content_elements = null;
    702         index_element = null;
    703     }
    704     index_elements = null;
    705     return text.toString();
    706     }
    707 
    708     static private String indexDefaultToString(Element command_element, boolean show_extracted_namespace) {
    709     StringBuffer text = new StringBuffer("");
    710     if(command_element.getAttribute(StaticStrings.ASSIGNED_ATTRIBUTE).equals(StaticStrings.FALSE_STR)) {
    711         text.append("#");
    712     }
    713     text.append(StaticStrings.INDEX_DEFAULT_STR);
    714     text.append(StaticStrings.TAB_CHARACTER);
    715     if (!command_element.getAttribute(StaticStrings.LEVEL_ATTRIBUTE).equals("")) {
    716         text.append(command_element.getAttribute(StaticStrings.LEVEL_ATTRIBUTE));
    717         text.append(StaticStrings.COLON_CHARACTER);
    718     }
    719     NodeList content_elements = command_element.getElementsByTagName(StaticStrings.CONTENT_ELEMENT);
    720     int content_elements_length = content_elements.getLength();
    721     for(int j = 0; j < content_elements_length; j++) {
    722         Element content_element = (Element) content_elements.item(j);
    723         String name_str = content_element.getAttribute(StaticStrings.NAME_ATTRIBUTE);
    724         if(!show_extracted_namespace && name_str.startsWith(StaticStrings.EXTRACTED_NAMESPACE)) {
    725         name_str = name_str.substring(StaticStrings.EXTRACTED_NAMESPACE.length());
    726         }
    727         text.append(name_str);
    728         name_str = null;
    729         if(j < content_elements_length - 1) {
    730         text.append(StaticStrings.COMMA_CHARACTER);
    731         }
    732         content_element = null;
    733     }
    734     content_elements = null;
    735     return text.toString();
    736     }
    737 
    738     static private String languagesToString(Element command_element) {
    739     StringBuffer text = new StringBuffer(StaticStrings.LANGUAGES_STR);
    740     text.append(StaticStrings.TAB_CHARACTER);
    741     // Retrieve all the languages and write them out in a space separated list
    742     NodeList language_elements = command_element.getElementsByTagName(StaticStrings.LANGUAGE_ELEMENT);
    743     int language_elements_length = language_elements.getLength();
    744     if(language_elements_length == 0) {
    745         return null;
    746     }
    747     for(int j = 0; j < language_elements_length; j++) {
    748         Element language_element = (Element) language_elements.item(j);
    749         text.append(language_element.getAttribute(StaticStrings.NAME_ATTRIBUTE));
    750         if(j < language_elements_length - 1) {
    751         text.append(StaticStrings.SPACE_CHARACTER);
    752         }
    753     }
    754     return text.toString();
    755     }
    756 
    757     static private String languageDefaultToString(Element command_element) {
    758     StringBuffer text = new StringBuffer(StaticStrings.LANGUAGE_DEFAULT_STR);
    759     text.append(StaticStrings.TAB_CHARACTER);
    760     text.append(command_element.getAttribute(StaticStrings.NAME_ATTRIBUTE));
    761     return text.toString();
    762     }
    763 
    764     static private String languageMetadataToString(Element command_element, boolean show_extracted_namespace) {
    765     if (!command_element.getAttribute(StaticStrings.ASSIGNED_ATTRIBUTE).equals(StaticStrings.TRUE_STR)) {
    766         return "";
    767     }
    768     StringBuffer text = new StringBuffer(StaticStrings.LANGUAGE_METADATA_STR);
    769     text.append(StaticStrings.TAB_CHARACTER);
    770     String name_str = command_element.getAttribute(StaticStrings.NAME_ATTRIBUTE);
    771     if(!show_extracted_namespace && name_str.startsWith(StaticStrings.EXTRACTED_NAMESPACE)) {
    772         name_str = name_str.substring(StaticStrings.EXTRACTED_NAMESPACE.length());
    773     }
    774     text.append(name_str);
    775     return text.toString();
    776     }
    777    
    778     static private String indexOptionsToString(Element command_element) {
    779     StringBuffer text = new StringBuffer("");
    780     if(command_element.getAttribute(StaticStrings.ASSIGNED_ATTRIBUTE).equals(StaticStrings.FALSE_STR)) {
    781         text.append("#");
    782     }
    783     text.append(command_element.getAttribute(StaticStrings.NAME_ATTRIBUTE));
    784     text.append(StaticStrings.TAB_CHARACTER);
    785     NodeList content_elements = command_element.getElementsByTagName(StaticStrings.INDEXOPTION_ELEMENT);
    786     int content_elements_length = content_elements.getLength();
    787     // Don't output anything if no options are set.
    788     if(content_elements_length == 0) {
    789         return null;
    790     }
    791     for(int i = 0; i < content_elements_length; i++) {
    792         Element content_element = (Element) content_elements.item(i);
    793         text.append(content_element.getAttribute(StaticStrings.NAME_ATTRIBUTE));
    794         text.append(StaticStrings.SPACE_CHARACTER);
    795     }
    796     return text.substring(0, text.length() - 1);
    797     }
    798 
    799     static private String indexOptionDefaultToString(Element command_element) {
    800     // Don't bother if there is no value
    801     if (command_element.getAttribute(StaticStrings.VALUE_ATTRIBUTE).equals("")) {
    802         return "";
    803     }
    804     StringBuffer text = new StringBuffer("");
    805     if(command_element.getAttribute(StaticStrings.ASSIGNED_ATTRIBUTE).equals(StaticStrings.FALSE_STR)) {
    806         text.append("#");
    807     }
    808     text.append(command_element.getAttribute(StaticStrings.NAME_ATTRIBUTE));
    809     text.append(StaticStrings.TAB_CHARACTER);
    810     text.append(command_element.getAttribute(StaticStrings.VALUE_ATTRIBUTE));
    811     return text.toString();
    812     }
    813    
    814     static private String metadataToString(Element command_element, boolean text_value) {
    815     // lets first check the value - if its empty, don't bother sticking it in the config file
    816     String value_str = XMLTools.getValue(command_element);
    817     if (value_str.equals("")) {
    818         return "";
    819     }
    820     boolean special = false;
    821    
    822     StringBuffer text = new StringBuffer("");
    823     String name_str = command_element.getAttribute(StaticStrings.NAME_ATTRIBUTE);
    824     // If the name is one of the special four, we don't write the collectionmeta first. Note maintainer and buildtype are singled out for 'prittying' reasons.
    825     if(name_str.equals(StaticStrings.COLLECTIONMETADATA_MAINTAINER_STR)|| name_str.equals(StaticStrings.BUILDTYPE_STR) ) {
    826         text.append(name_str);
    827         text.append(StaticStrings.TAB_CHARACTER);
    828         special = true;
    829     }
    830     else if (name_str.equals(StaticStrings.COLLECTIONMETADATA_CREATOR_STR) || name_str.equals(StaticStrings.COLLECTIONMETADATA_PUBLIC_STR) ) {
    831         text.append(name_str);
    832         text.append(StaticStrings.TAB_CHARACTER);
    833         text.append(StaticStrings.TAB_CHARACTER);
    834         special = true;
    835     }
    836     else {
    837         text.append(StaticStrings.COLLECTIONMETADATA_STR);
    838         text.append(StaticStrings.TAB_CHARACTER);
    839         text.append(name_str);
    840         text.append(StaticStrings.SPACE_CHARACTER);
    841         String language_str = command_element.getAttribute(StaticStrings.LANGUAGE_ATTRIBUTE);
    842         text.append(StaticStrings.LBRACKET_CHARACTER);
    843         text.append(StaticStrings.LANGUAGE_ARGUMENT);
    844         text.append(language_str);
    845         text.append(StaticStrings.RBRACKET_CHARACTER);
    846         text.append(StaticStrings.SPACE_CHARACTER);
    847     }
    848     name_str = null;
    849 
    850     // The value string we retrieved will be encoded for xml, so we now decode it - to text if text_value set. This parameter was originally show_extracted_namespace, but sincethis is only true for 'toString()' commands from within the CDM, its good enough to determine if this toString() will be used to display on screen, or write to collect.cfg
    851     if(text_value == CollectionMeta.TEXT) {
    852         value_str = Codec.transform(value_str, Codec.DOM_TO_TEXT);
    853     }
    854     else {
    855         value_str = Codec.transform(value_str, Codec.DOM_TO_GREENSTONE);
    856     }
    857 
    858     // We don't wrap the email addresses in quotes, nor the other special metadata
    859     if(special) {
    860         text.append(value_str);
    861     }
    862     else {
    863         text.append(StaticStrings.SPEECH_CHARACTER);
    864         text.append(value_str);
    865         text.append(StaticStrings.SPEECH_CHARACTER);
    866     }
    867     value_str = null;
    868     return text.toString();
    869     }
    870 
    871     /** Parse a collect.cfg into a DOM model representation. 
     514    static private Element getOrCreateElementByTagName (String name, String conditional_attribute, String required_value) {
     515        Element document_element = document.getDocumentElement ();
     516        NodeList elements = document_element.getElementsByTagName (name);
     517        int elements_length = elements.getLength ();
     518        if(elements_length > 0) {
     519            if(conditional_attribute == null) {
     520                document_element = null;
     521                return (Element) elements.item (0);
     522            }
     523            else {
     524                for(int i = 0; i < elements_length; i++) {
     525                    Element element = (Element) elements.item (i);
     526                    if(element.getAttribute (conditional_attribute).equals (required_value)) {
     527                        document_element = null;
     528                        return element;
     529                    }
     530                    element = null;
     531                }
     532            }
     533        }
     534        // Create the element
     535        Element element = document.createElement (name);
     536        // If there was a property set it
     537        if(conditional_attribute != null) {
     538            element.setAttribute (conditional_attribute, required_value);
     539        }
     540        Node target_node = findInsertionPoint (element);
     541        if(target_node != null) {
     542            document_element.insertBefore (element, target_node);
     543        }
     544        else {
     545            document_element.appendChild (element);
     546        }
     547        document_element = null;
     548        return element;
     549    }
     550   
     551    static private String indexesToString (Element command_element, boolean show_extracted_namespace) {
     552        boolean comment_only = false;
     553        StringBuffer text = new StringBuffer ("");
     554        if(command_element.getAttribute (StaticStrings.ASSIGNED_ATTRIBUTE).equals (StaticStrings.FALSE_STR)) {
     555            text.append ("#");
     556            comment_only = true;
     557        }
     558        text.append (StaticStrings.INDEX_STR);
     559        text.append (StaticStrings.TAB_CHARACTER);
     560        if(!comment_only) {
     561            text.append (StaticStrings.TAB_CHARACTER);
     562        }
     563        NodeList index_elements = command_element.getElementsByTagName (StaticStrings.INDEX_ELEMENT);
     564        if (index_elements.getLength () == 0) { // no indexes
     565            return "";
     566        }
     567        // For each index, write its level, a colon, then concatenate its child content elements into a single comma separated list
     568        int index_elements_length = index_elements.getLength ();
     569        for(int j = 0; j < index_elements_length; j++) {
     570            Element index_element = (Element) index_elements.item (j);
     571            String level_str = index_element.getAttribute (StaticStrings.LEVEL_ATTRIBUTE);
     572            if(level_str.length () > 0) {
     573                text.append (level_str);
     574                text.append (StaticStrings.COLON_CHARACTER);
     575            }
     576            NodeList content_elements = index_element.getElementsByTagName (StaticStrings.CONTENT_ELEMENT);
     577            int content_elements_length = content_elements.getLength ();
     578            // Don't output anything if no indexes are set
     579            if(content_elements_length == 0) {
     580                return null;
     581            }
     582            for(int k = 0; k < content_elements_length; k++) {
     583                Element content_element = (Element) content_elements.item (k);
     584                String name_str = content_element.getAttribute (StaticStrings.NAME_ATTRIBUTE);
     585                if(!show_extracted_namespace && name_str.startsWith (StaticStrings.EXTRACTED_NAMESPACE)) {
     586                    name_str = name_str.substring (StaticStrings.EXTRACTED_NAMESPACE.length ());
     587                }
     588                text.append (name_str);
     589                name_str = null;
     590                if(k < content_elements_length - 1) {
     591                    text.append (StaticStrings.COMMA_CHARACTER);
     592                }
     593                content_element = null;
     594            }
     595            if(j < index_elements_length - 1) {
     596                text.append (StaticStrings.SPACE_CHARACTER);
     597            }
     598            content_elements = null;
     599            index_element = null;
     600        }
     601        index_elements = null;
     602        return text.toString ();
     603    }
     604   
     605    static private String indexDefaultToString (Element command_element, boolean show_extracted_namespace) {
     606        StringBuffer text = new StringBuffer ("");
     607        if(command_element.getAttribute (StaticStrings.ASSIGNED_ATTRIBUTE).equals (StaticStrings.FALSE_STR)) {
     608            text.append ("#");
     609        }
     610        text.append (StaticStrings.INDEX_DEFAULT_STR);
     611        text.append (StaticStrings.TAB_CHARACTER);
     612        if (!command_element.getAttribute (StaticStrings.LEVEL_ATTRIBUTE).equals ("")) {
     613            text.append (command_element.getAttribute (StaticStrings.LEVEL_ATTRIBUTE));
     614            text.append (StaticStrings.COLON_CHARACTER);
     615        }
     616        NodeList content_elements = command_element.getElementsByTagName (StaticStrings.CONTENT_ELEMENT);
     617        int content_elements_length = content_elements.getLength ();
     618        for(int j = 0; j < content_elements_length; j++) {
     619            Element content_element = (Element) content_elements.item (j);
     620            String name_str = content_element.getAttribute (StaticStrings.NAME_ATTRIBUTE);
     621            if(!show_extracted_namespace && name_str.startsWith (StaticStrings.EXTRACTED_NAMESPACE)) {
     622                name_str = name_str.substring (StaticStrings.EXTRACTED_NAMESPACE.length ());
     623            }
     624            text.append (name_str);
     625            name_str = null;
     626            if(j < content_elements_length - 1) {
     627                text.append (StaticStrings.COMMA_CHARACTER);
     628            }
     629            content_element = null;
     630        }
     631        content_elements = null;
     632        return text.toString ();
     633    }
     634   
     635    static private String languagesToString (Element command_element) {
     636        StringBuffer text = new StringBuffer (StaticStrings.LANGUAGES_STR);
     637        text.append (StaticStrings.TAB_CHARACTER);
     638        // Retrieve all the languages and write them out in a space separated list
     639        NodeList language_elements = command_element.getElementsByTagName (StaticStrings.LANGUAGE_ELEMENT);
     640        int language_elements_length = language_elements.getLength ();
     641        if(language_elements_length == 0) {
     642            return null;
     643        }
     644        for(int j = 0; j < language_elements_length; j++) {
     645            Element language_element = (Element) language_elements.item (j);
     646            text.append (language_element.getAttribute (StaticStrings.NAME_ATTRIBUTE));
     647            if(j < language_elements_length - 1) {
     648                text.append (StaticStrings.SPACE_CHARACTER);
     649            }
     650        }
     651        return text.toString ();
     652    }
     653   
     654    static private String languageDefaultToString (Element command_element) {
     655        StringBuffer text = new StringBuffer (StaticStrings.LANGUAGE_DEFAULT_STR);
     656        text.append (StaticStrings.TAB_CHARACTER);
     657        text.append (command_element.getAttribute (StaticStrings.NAME_ATTRIBUTE));
     658        return text.toString ();
     659    }
     660   
     661    static private String languageMetadataToString (Element command_element, boolean show_extracted_namespace) {
     662        if (!command_element.getAttribute (StaticStrings.ASSIGNED_ATTRIBUTE).equals (StaticStrings.TRUE_STR)) {
     663            return "";
     664        }
     665        StringBuffer text = new StringBuffer (StaticStrings.LANGUAGE_METADATA_STR);
     666        text.append (StaticStrings.TAB_CHARACTER);
     667        String name_str = command_element.getAttribute (StaticStrings.NAME_ATTRIBUTE);
     668        if(!show_extracted_namespace && name_str.startsWith (StaticStrings.EXTRACTED_NAMESPACE)) {
     669            name_str = name_str.substring (StaticStrings.EXTRACTED_NAMESPACE.length ());
     670        }
     671        text.append (name_str);
     672        return text.toString ();
     673    }
     674   
     675    static private String indexOptionsToString (Element command_element) {
     676        StringBuffer text = new StringBuffer ("");
     677        if(command_element.getAttribute (StaticStrings.ASSIGNED_ATTRIBUTE).equals (StaticStrings.FALSE_STR)) {
     678            text.append ("#");
     679        }
     680        text.append (command_element.getAttribute (StaticStrings.NAME_ATTRIBUTE));
     681        text.append (StaticStrings.TAB_CHARACTER);
     682        NodeList content_elements = command_element.getElementsByTagName (StaticStrings.INDEXOPTION_ELEMENT);
     683        int content_elements_length = content_elements.getLength ();
     684        // Don't output anything if no options are set.
     685        if(content_elements_length == 0) {
     686            return null;
     687        }
     688        for(int i = 0; i < content_elements_length; i++) {
     689            Element content_element = (Element) content_elements.item (i);
     690            text.append (content_element.getAttribute (StaticStrings.NAME_ATTRIBUTE));
     691            text.append (StaticStrings.SPACE_CHARACTER);
     692        }
     693        return text.substring (0, text.length () - 1);
     694    }
     695   
     696    static private String indexOptionDefaultToString (Element command_element) {
     697        // Don't bother if there is no value
     698        if (command_element.getAttribute (StaticStrings.VALUE_ATTRIBUTE).equals ("")) {
     699            return "";
     700        }
     701        StringBuffer text = new StringBuffer ("");
     702        if(command_element.getAttribute (StaticStrings.ASSIGNED_ATTRIBUTE).equals (StaticStrings.FALSE_STR)) {
     703            text.append ("#");
     704        }
     705        text.append (command_element.getAttribute (StaticStrings.NAME_ATTRIBUTE));
     706        text.append (StaticStrings.TAB_CHARACTER);
     707        text.append (command_element.getAttribute (StaticStrings.VALUE_ATTRIBUTE));
     708        return text.toString ();
     709    }
     710   
     711    static private String metadataToString (Element command_element, boolean text_value) {
     712        // lets first check the value - if its empty, don't bother sticking it in the config file
     713        String value_str = XMLTools.getValue (command_element);
     714        if (value_str.equals ("")) {
     715            return "";
     716        }
     717        boolean special = false;
     718       
     719        StringBuffer text = new StringBuffer ("");
     720        String name_str = command_element.getAttribute (StaticStrings.NAME_ATTRIBUTE);
     721        // If the name is one of the special four, we don't write the collectionmeta first. Note maintainer and buildtype are singled out for 'prittying' reasons.
     722        if(name_str.equals (StaticStrings.COLLECTIONMETADATA_MAINTAINER_STR)|| name_str.equals (StaticStrings.BUILDTYPE_STR) ) {
     723            text.append (name_str);
     724            text.append (StaticStrings.TAB_CHARACTER);
     725            special = true;
     726        }
     727        else if (name_str.equals (StaticStrings.COLLECTIONMETADATA_CREATOR_STR) || name_str.equals (StaticStrings.COLLECTIONMETADATA_PUBLIC_STR) ) {
     728            text.append (name_str);
     729            text.append (StaticStrings.TAB_CHARACTER);
     730            text.append (StaticStrings.TAB_CHARACTER);
     731            special = true;
     732        }
     733        else {
     734            text.append (StaticStrings.COLLECTIONMETADATA_STR);
     735            text.append (StaticStrings.TAB_CHARACTER);
     736            text.append (name_str);
     737            text.append (StaticStrings.SPACE_CHARACTER);
     738            String language_str = command_element.getAttribute (StaticStrings.LANGUAGE_ATTRIBUTE);
     739            text.append (StaticStrings.LBRACKET_CHARACTER);
     740            text.append (StaticStrings.LANGUAGE_ARGUMENT);
     741            text.append (language_str);
     742            text.append (StaticStrings.RBRACKET_CHARACTER);
     743            text.append (StaticStrings.SPACE_CHARACTER);
     744        }
     745        name_str = null;
     746       
     747        // The value string we retrieved will be encoded for xml, so we now decode it - to text if text_value set. This parameter was originally show_extracted_namespace, but sincethis is only true for 'toString()' commands from within the CDM, its good enough to determine if this toString() will be used to display on screen, or write to collect.cfg
     748        if(text_value == CollectionMeta.TEXT) {
     749            value_str = Codec.transform (value_str, Codec.DOM_TO_TEXT);
     750        }
     751        else {
     752            value_str = Codec.transform (value_str, Codec.DOM_TO_GREENSTONE);
     753        }
     754       
     755        // We don't wrap the email addresses in quotes, nor the other special metadata
     756        if(special) {
     757            text.append (value_str);
     758        }
     759        else {
     760            text.append (StaticStrings.SPEECH_CHARACTER);
     761            text.append (value_str);
     762            text.append (StaticStrings.SPEECH_CHARACTER);
     763        }
     764        value_str = null;
     765        return text.toString ();
     766    }
     767   
     768    /** Parse a collect.cfg into a DOM model representation.
    872769     * note we are ignoring 2.39 compatibility now. */
    873     private void parse(File collect_cfg_file) {
    874     // hack for pre 2.71 compatibility - we need to add in a
    875     // build type if there is not one there
    876     boolean search_types_parsed = false;
    877     boolean build_types_parsed = false;
    878     try {
    879         saved_collect_cfg_string_buffer = new StringBuffer();
    880 
    881         Element collect_cfg_element = document.getDocumentElement();
    882         // Read in the file one command at a time.
    883         InputStream istream = new FileInputStream(collect_cfg_file);
    884         Reader in_reader = new InputStreamReader(istream, ENCODING);
    885         BufferedReader in = new BufferedReader(in_reader);
    886         String command_str = null;
    887         while((command_str = in.readLine()) != null) {
    888         saved_collect_cfg_string_buffer.append(command_str + "\n");
    889 
    890         boolean append_element = true;
    891         Element command_element = null;
    892         // A command may be broken over several lines.
    893         command_str = command_str.trim();
    894         boolean eof = false;
    895         while(!eof && command_str.endsWith(StaticStrings.NEWLINE_CHARACTER)) {
    896             String next_line = in.readLine();
    897             if(next_line != null) {
    898             next_line = next_line.trim();
    899             if(next_line.length() > 0) {
    900                 // Remove the new line character
    901                 command_str = command_str.substring(0, command_str.lastIndexOf(StaticStrings.NEWLINE_CHARACTER));
    902                 // And append the next line, which due to the test above must be non-zero length
    903                 command_str = command_str + next_line;
    904             }
    905             next_line = null;
    906             }
    907             // If we've reached the end of the file theres nothing more we can do
    908             else {
    909             eof = true;
    910             }
    911         }
    912         // If there is still a new line character, then we remove it and hope for the best
    913         if(command_str.endsWith(StaticStrings.NEWLINE_CHARACTER)) {
    914             command_str = command_str.substring(0, command_str.lastIndexOf(StaticStrings.NEWLINE_CHARACTER));
    915         }
    916         // Now we've either got a command to parse...
    917         if(command_str.length() != 0) {
    918             // Start trying to figure out what it is
    919             //StringTokenizer tokenizer = new StringTokenizer(command_str);
    920             // Instead of a standard string tokenizer I'm going to use the new version of CommandTokenizer, which is not only smart enough to correctly notice speech marks and correctly parse them out, but now also takes the input stream so it can rebuild tokens that stretch over several lines.
    921             CommandTokenizer tokenizer = new CommandTokenizer(command_str, in);
    922             String command_type = tokenizer.nextToken().toLowerCase();
    923             // Why can't you switch on strings eh? We pass it to the various subparsers who each have a bash at parsing the command. If none can parse the command, an unknown element is created
    924             if(command_element == null && command_type.equals(StaticStrings.CLASSIFY_STR)) {
    925             command_element = parseClassify(command_str);
    926             }
    927             if(command_element == null && command_type.equals(StaticStrings.FORMAT_STR)) {
    928             command_element = parseFormat(tokenizer); // Revised to handle multiple lines
    929             }
    930             if(command_element == null && (command_type.equals(StaticStrings.INDEX_STR)  || command_type.equals(StaticStrings.COMMENTED_INDEXES_STR))) {
    931             command_element = parseIndex(command_str);
    932             }
    933             if(command_element == null && (command_type.equals(StaticStrings.INDEX_DEFAULT_STR) || command_type.equals(StaticStrings.COMMENTED_INDEX_DEFAULT_STR))) {
    934            
    935             command_element = parseIndexDefault(command_str);
    936             }
    937             if(command_element == null && command_type.equals(StaticStrings.LANGUAGES_STR)) {
    938             command_element = parseLanguage(command_str);
    939             }
    940             if(command_element == null && command_type.equals(StaticStrings.LANGUAGE_DEFAULT_STR)) {
    941             command_element = parseLanguageDefault(command_str);
    942             }
    943             if (command_element == null && command_type.equals(StaticStrings.LANGUAGE_METADATA_STR)) {
    944             command_element = parseLanguageMetadata(command_str);
    945             }
    946             if(command_element == null && command_type.equals(StaticStrings.LEVELS_STR)) {
    947             command_element = parseIndexOptions(command_str, StaticStrings.LEVELS_STR, true);
    948             }
    949             if (command_element == null && command_type.equals(StaticStrings.COMMENTED_LEVELS_STR)) {
    950             command_element = parseIndexOptions(command_str, StaticStrings.LEVELS_STR, false);
    951             }
    952             if(command_element == null && command_type.equals(StaticStrings.LEVEL_DEFAULT_STR)) {
    953             command_element = parseIndexOptionDefault(command_str, StaticStrings.LEVEL_DEFAULT_STR, true);
    954             }
    955             if(command_element == null && command_type.equals(StaticStrings.COMMENTED_LEVEL_DEFAULT_STR)) {
    956             command_element = parseIndexOptionDefault(command_str, StaticStrings.LEVEL_DEFAULT_STR, false);
    957             }
    958             if (command_element == null && command_type.equals(StaticStrings.STEMOPTIONS_STR)) {
    959             command_element = parseIndexOptions(command_str, StaticStrings.STEMOPTIONS_STR, true);
    960             }
    961             if (command_element == null && command_type.equals(StaticStrings.COMMENTED_STEMOPTIONS_STR)) {
    962             command_element = parseIndexOptions(command_str, StaticStrings.STEMOPTIONS_STR, false);
    963             }
    964             if(command_element == null && command_type.equals(StaticStrings.COLLECTIONMETADATA_STR)) {
    965             command_element = parseMetadata(tokenizer); // Revised to handle multiple lines
    966             }
    967             if(command_element == null && (command_type.equals(StaticStrings.COLLECTIONMETADATA_PUBLIC_STR) || command_type.equals(StaticStrings.COLLECTIONMETADATA_CREATOR_STR) || command_type.equals(StaticStrings.COLLECTIONMETADATA_MAINTAINER_STR) || command_type.equals(StaticStrings.BUILDTYPE_STR))) {
    968             command_element = parseMetadataSpecial(command_str);
    969             // pre 2.71 hack
    970             if (command_type.equals(StaticStrings.BUILDTYPE_STR)) {
    971                 build_types_parsed = true;
    972             }
    973             }
    974             if(command_element == null && command_type.equals(StaticStrings.PLUGIN_STR)) {
    975             command_element = parsePlugin(command_str);
    976             }
    977             // leave here for backwards compatibility
    978             if(command_element == null && command_type.equals(StaticStrings.SEARCHTYPE_STR)) {
    979             command_element = parseSearchType(command_str);
    980             // pre 2.71 hack
    981             search_types_parsed = true;
    982            
    983             }
    984             if(command_element == null && command_type.equals(StaticStrings.SUBCOLLECTION_STR)) {
    985             command_element = parseSubCollection(command_str);
    986             }
    987             if(command_element == null && command_type.equals(StaticStrings.SUBCOLLECTION_DEFAULT_INDEX_STR)) {
    988             command_element = parseSubCollectionDefaultIndex(command_str);
    989             }
    990             if(command_element == null && command_type.equals(StaticStrings.SUBCOLLECTION_INDEX_STR)) {
    991             command_element = parseSubCollectionIndex(command_str);
    992             }
    993             if(command_element == null && (command_type.equals(StaticStrings.SUPERCOLLECTION_STR) || command_type.equals(StaticStrings.CCS_STR))) {
    994             command_element = parseSuperCollection(command_str);
    995             }
    996             // Doesn't match any known type
    997             command_type = null;
    998             if(command_element == null) {
    999             // No-one knows what to do with this command, so we create an Unknown command element
    1000             command_element = document.createElement(StaticStrings.UNKNOWN_ELEMENT);
    1001             XMLTools.setValue(command_element, command_str);
    1002             }
    1003         }
    1004         // Or an empty line to remember for later
    1005         else {
    1006             command_element = document.createElement(NEWLINE_ELEMENT);
    1007         }
    1008         // Now command element shouldn't be null so we append it to the collection config DOM, but only if we haven't been told not to add it
    1009         //if(append_element) {
    1010             collect_cfg_element.appendChild(command_element);
    1011             //}
    1012         }
    1013         if (!build_types_parsed) {
    1014         String buildtype_type = BuildTypeManager.BUILD_TYPE_MG;
    1015         if (search_types_parsed) {
    1016             buildtype_type = BuildTypeManager.BUILD_TYPE_MGPP;
    1017         }
    1018         Element command_element = parseMetadataSpecial(StaticStrings.BUILDTYPE_STR+"  "+buildtype_type);
    1019         Node target_node = findInsertionPoint(command_element);
    1020         if(target_node != null) {
    1021             collect_cfg_element.insertBefore(command_element, target_node);
    1022         }
    1023         else {
    1024             collect_cfg_element.appendChild(command_element);
    1025         }
    1026 
    1027         }
    1028     }
    1029     catch(Exception exception) {
    1030         DebugStream.println("Error in CollectionConfiguration.parse(java.io.File): " + exception);
    1031         DebugStream.printStackTrace(exception);
    1032     }
    1033     }
    1034    
    1035  
    1036     private Element parseClassify(String command_str) {
    1037     Element command_element = null;
    1038     try {
    1039         CommandTokenizer tokenizer = new CommandTokenizer(command_str);
    1040         // Check the token count. The token count from a command tokenizer isn't guarenteed to be correct, but it does give the maximum number of available tokens according to the underlying StringTokenizer (some of which may actually be append together by the CommandTokenizer as being a single argument).
    1041         if(tokenizer.countTokens() >= 2) {  // Must support "classify Phind" (no args)
    1042         command_element = document.createElement(StaticStrings.CLASSIFY_ELEMENT);
    1043         // First token is classify
    1044         tokenizer.nextToken();
    1045         // The next token is the classifier type
    1046         command_element.setAttribute(StaticStrings.TYPE_ATTRIBUTE, tokenizer.nextToken());
    1047         // Now we parse out the remaining arguments into a hashmapping from name to value
    1048         HashMap arguments = parseArguments(tokenizer);
    1049         // Assign the arguments as Option elements, but watch out for the metadata argument as we treat that differently
    1050         Iterator names = arguments.keySet().iterator();
    1051         while(names.hasNext()) {
    1052             String name = (String) names.next();
    1053             String value = (String) arguments.get(name); // Can be null
    1054             // The metadata argument gets added as the content attribute
    1055             if (name.equals(StaticStrings.METADATA_ARGUMENT) && value != null) {
    1056             // Add the extracted namespace onto un-namespaced metadata names
    1057             StringTokenizer string_tokenizer = new StringTokenizer(value, ",");
    1058             value = "";
    1059             while (string_tokenizer.hasMoreElements()) {
    1060                 String token = (String) string_tokenizer.nextElement();
    1061 
    1062                 if (token.indexOf(StaticStrings.NS_SEP) == -1) {
    1063                 token = StaticStrings.EXTRACTED_NAMESPACE + token;
    1064                 }
    1065                 else {
    1066                 MetadataElement metadata_element = MetadataTools.getMetadataElementWithName(token);
    1067                 if (metadata_element != null) {
    1068                     token = metadata_element.getDisplayName();
    1069                 }
    1070                 }
    1071 
    1072                 if (!value.equals("")) {
    1073                 value = value + ",";
    1074                 }
    1075                 value = value + token;
    1076             }
    1077             }
    1078             // Everything else is an Option Element
    1079             Element option_element = document.createElement(StaticStrings.OPTION_ELEMENT);
    1080             option_element.setAttribute(StaticStrings.NAME_ATTRIBUTE, name.substring(1));
    1081             if(value != null) {
    1082             // Remove any speech marks appended in strings containing whitespace
    1083             if(value.startsWith(StaticStrings.SPEECH_CHARACTER) && value.endsWith(StaticStrings.SPEECH_CHARACTER)) {
    1084                 value = value.substring(1, value.length() - 1);
    1085             }
    1086             XMLTools.setValue(option_element, value);
    1087             }
    1088             option_element.setAttribute(StaticStrings.ASSIGNED_ATTRIBUTE, StaticStrings.TRUE_STR);
    1089             command_element.appendChild(option_element);
    1090             option_element = null;
    1091             name = null;
    1092             value = null;
    1093         }
    1094         names = null;
    1095         arguments = null;
    1096         }
    1097         tokenizer = null;
    1098     }
    1099     catch(Exception error) {
    1100     }
    1101     return command_element;
    1102     }
    1103 
    1104     private Element parseFormat(CommandTokenizer tokenizer) {
    1105     Element command_element = null;
    1106     try {
    1107         command_element = document.createElement(StaticStrings.FORMAT_ELEMENT);
    1108         String name_str = tokenizer.nextToken();
    1109         String value_str = tokenizer.nextToken();
    1110         if(name_str != null && value_str != null) {
    1111         command_element.setAttribute(StaticStrings.NAME_ATTRIBUTE, name_str);
    1112         // If the value is true or false we add it as an attribute
    1113         if(value_str.equalsIgnoreCase(StaticStrings.TRUE_STR) || value_str.equalsIgnoreCase(StaticStrings.FALSE_STR)) {
    1114             command_element.setAttribute(StaticStrings.VALUE_ATTRIBUTE, value_str.toLowerCase());
    1115         }
    1116         // Otherwise it gets added as a text node
    1117         else {
    1118             // Ready the value str (which can contain all sorts of funky characters) for writing as a DOM value
    1119             value_str = Codec.transform(value_str, Codec.GREENSTONE_TO_DOM);
    1120             XMLTools.setValue(command_element, value_str);
    1121         }
    1122         }
    1123         else {
    1124         command_element = null;
    1125         }
    1126         name_str = null;
    1127         value_str = null;
    1128     }
    1129     catch (Exception exception) {
    1130         DebugStream.printStackTrace(exception);
    1131         command_element = null;
    1132     }
    1133     return command_element;
    1134     }
    1135 
    1136     private Element parseIndex(String command_str) {
    1137     Element command_element = null;
    1138     try {
    1139         StringTokenizer tokenizer = new StringTokenizer(command_str);
    1140         String command = tokenizer.nextToken();
    1141         command_element = document.createElement(StaticStrings.INDEXES_ELEMENT);
    1142         command_element.setAttribute(StaticStrings.ASSIGNED_ATTRIBUTE, (command.equals(StaticStrings.INDEX_STR) ? StaticStrings.TRUE_STR : StaticStrings.FALSE_STR));
    1143         command = null;
    1144         if(!tokenizer.hasMoreTokens()) {
    1145 
    1146         // there are no indexes
    1147         command_element.setAttribute(StaticStrings.ASSIGNED_ATTRIBUTE, StaticStrings.FALSE_STR);
    1148         command_element.setAttribute(StaticStrings.MGPP_ATTRIBUTE, StaticStrings.FALSE_STR); // for now
    1149         tokenizer = null;
    1150         return command_element;
    1151         }
    1152 
    1153         while(tokenizer.hasMoreTokens()) {
    1154         Element index_element = document.createElement(StaticStrings.INDEX_ELEMENT);
    1155         String index_str = tokenizer.nextToken();
    1156         // There are two types of index we have to consider. Old G2.38 and earlier use level:source tuplets while G2.39+ have just a single, non-comma separated list where order is important.
    1157         boolean old_index;
    1158         if(index_str.indexOf(StaticStrings.COLON_CHARACTER) != -1) {
    1159             old_index = true;
    1160             index_element.setAttribute(StaticStrings.LEVEL_ATTRIBUTE, index_str.substring(0, index_str.indexOf(StaticStrings.COLON_CHARACTER)));
    1161             index_str = index_str.substring(index_str.indexOf(StaticStrings.COLON_CHARACTER) + 1);
    1162             command_element.setAttribute(StaticStrings.MGPP_ATTRIBUTE, StaticStrings.FALSE_STR);
    1163         }
    1164         else {
    1165             command_element.setAttribute(StaticStrings.MGPP_ATTRIBUTE, StaticStrings.TRUE_STR);
    1166             old_index = false;
    1167         }
    1168         StringTokenizer content_tokenizer = new StringTokenizer(index_str, StaticStrings.COMMA_CHARACTER);
    1169         while(content_tokenizer.hasMoreTokens()) {
    1170             Element content_element = document.createElement(StaticStrings.CONTENT_ELEMENT);
    1171             String content_str = content_tokenizer.nextToken();
    1172             // Since the contents of indexes have to be certain keywords, or metadata elements, if the content isn't a keyword and doesn't yet have a namespace, append the extracted metadata namespace.
    1173             if(content_str.indexOf(StaticStrings.NS_SEP) == -1) {
    1174             if(content_str.equals(StaticStrings.TEXT_STR) || (!old_index && content_str.equals(StaticStrings.ALLFIELDS_STR))) {
    1175                 // Our special strings are OK.
    1176             }
    1177             else {
    1178                 content_str = StaticStrings.EXTRACTED_NAMESPACE + content_str;
    1179             }
    1180             }
    1181             content_element.setAttribute(StaticStrings.NAME_ATTRIBUTE, content_str);
    1182             index_element.appendChild(content_element);
    1183             content_element = null;
    1184         }
    1185         content_tokenizer = null;
    1186         index_str = null;
    1187         command_element.appendChild(index_element);
    1188         index_element = null;
    1189         }
    1190         tokenizer = null;
    1191     }
    1192     catch (Exception exception) {
    1193         exception.printStackTrace();
    1194     }
    1195     return command_element;
    1196     }
    1197 
    1198     private Element parseIndexDefault(String command_str) {
    1199     Element command_element = null;
    1200         try {
    1201         StringTokenizer tokenizer = new StringTokenizer(command_str);
    1202         if(tokenizer.countTokens() >= 2) {
    1203         command_element = document.createElement(StaticStrings.INDEX_DEFAULT_ELEMENT);                 
    1204         command_element.setAttribute(StaticStrings.ASSIGNED_ATTRIBUTE, ((tokenizer.nextToken()).equals(StaticStrings.INDEX_DEFAULT_STR) ? StaticStrings.TRUE_STR : StaticStrings.FALSE_STR));
    1205         String index_str = tokenizer.nextToken();
     770    private void parse (File collect_cfg_file) {
     771        // hack for pre 2.71 compatibility - we need to add in a
     772        // build type if there is not one there
     773        boolean search_types_parsed = false;
     774        boolean build_types_parsed = false;
     775        try {
     776            saved_collect_cfg_string_buffer = new StringBuffer ();
     777           
     778            Element collect_cfg_element = document.getDocumentElement ();
     779            // Read in the file one command at a time.
     780            InputStream istream = new FileInputStream (collect_cfg_file);
     781            Reader in_reader = new InputStreamReader (istream, ENCODING);
     782            BufferedReader in = new BufferedReader (in_reader);
     783            String command_str = null;
     784            while((command_str = in.readLine ()) != null) {
     785                saved_collect_cfg_string_buffer.append (command_str + "\n");
     786               
     787                boolean append_element = true;
     788                Element command_element = null;
     789                // A command may be broken over several lines.
     790                command_str = command_str.trim ();
     791                boolean eof = false;
     792                while(!eof && command_str.endsWith (StaticStrings.NEWLINE_CHARACTER)) {
     793                    String next_line = in.readLine ();
     794                    if(next_line != null) {
     795                        next_line = next_line.trim ();
     796                        if(next_line.length () > 0) {
     797                            // Remove the new line character
     798                            command_str = command_str.substring (0, command_str.lastIndexOf (StaticStrings.NEWLINE_CHARACTER));
     799                            // And append the next line, which due to the test above must be non-zero length
     800                            command_str = command_str + next_line;
     801                        }
     802                        next_line = null;
     803                    }
     804                    // If we've reached the end of the file theres nothing more we can do
     805                    else {
     806                        eof = true;
     807                    }
     808                }
     809                // If there is still a new line character, then we remove it and hope for the best
     810                if(command_str.endsWith (StaticStrings.NEWLINE_CHARACTER)) {
     811                    command_str = command_str.substring (0, command_str.lastIndexOf (StaticStrings.NEWLINE_CHARACTER));
     812                }
     813                // Now we've either got a command to parse...
     814                if(command_str.length () != 0) {
     815                    // Start trying to figure out what it is
     816                    //StringTokenizer tokenizer = new StringTokenizer(command_str);
     817                    // Instead of a standard string tokenizer I'm going to use the new version of CommandTokenizer, which is not only smart enough to correctly notice speech marks and correctly parse them out, but now also takes the input stream so it can rebuild tokens that stretch over several lines.
     818                    CommandTokenizer tokenizer = new CommandTokenizer (command_str, in);
     819                    String command_type = tokenizer.nextToken ().toLowerCase ();
     820                    // Why can't you switch on strings eh? We pass it to the various subparsers who each have a bash at parsing the command. If none can parse the command, an unknown element is created
     821                    if(command_element == null && command_type.equals (StaticStrings.CLASSIFY_STR)) {
     822                        command_element = parseClassify (command_str);
     823                    }
     824                    if(command_element == null && command_type.equals (StaticStrings.FORMAT_STR)) {
     825                        command_element = parseFormat (tokenizer); // Revised to handle multiple lines
     826                    }
     827                    if(command_element == null && (command_type.equals (StaticStrings.INDEX_STR)  || command_type.equals (StaticStrings.COMMENTED_INDEXES_STR))) {
     828                        command_element = parseIndex (command_str);
     829                    }
     830                    if(command_element == null && (command_type.equals (StaticStrings.INDEX_DEFAULT_STR) || command_type.equals (StaticStrings.COMMENTED_INDEX_DEFAULT_STR))) {
     831                       
     832                        command_element = parseIndexDefault (command_str);
     833                    }
     834                    if(command_element == null && command_type.equals (StaticStrings.LANGUAGES_STR)) {
     835                        command_element = parseLanguage (command_str);
     836                    }
     837                    if(command_element == null && command_type.equals (StaticStrings.LANGUAGE_DEFAULT_STR)) {
     838                        command_element = parseLanguageDefault (command_str);
     839                    }
     840                    if (command_element == null && command_type.equals (StaticStrings.LANGUAGE_METADATA_STR)) {
     841                        command_element = parseLanguageMetadata (command_str);
     842                    }
     843                    if(command_element == null && command_type.equals (StaticStrings.LEVELS_STR)) {
     844                        command_element = parseIndexOptions (command_str, StaticStrings.LEVELS_STR, true);
     845                    }
     846                    if (command_element == null && command_type.equals (StaticStrings.COMMENTED_LEVELS_STR)) {
     847                        command_element = parseIndexOptions (command_str, StaticStrings.LEVELS_STR, false);
     848                    }
     849                    if(command_element == null && command_type.equals (StaticStrings.LEVEL_DEFAULT_STR)) {
     850                        command_element = parseIndexOptionDefault (command_str, StaticStrings.LEVEL_DEFAULT_STR, true);
     851                    }
     852                    if(command_element == null && command_type.equals (StaticStrings.COMMENTED_LEVEL_DEFAULT_STR)) {
     853                        command_element = parseIndexOptionDefault (command_str, StaticStrings.LEVEL_DEFAULT_STR, false);
     854                    }
     855                    if (command_element == null && command_type.equals (StaticStrings.STEMOPTIONS_STR)) {
     856                        command_element = parseIndexOptions (command_str, StaticStrings.STEMOPTIONS_STR, true);
     857                    }
     858                    if (command_element == null && command_type.equals (StaticStrings.COMMENTED_STEMOPTIONS_STR)) {
     859                        command_element = parseIndexOptions (command_str, StaticStrings.STEMOPTIONS_STR, false);
     860                    }
     861                    if(command_element == null && command_type.equals (StaticStrings.COLLECTIONMETADATA_STR)) {
     862                        command_element = parseMetadata (tokenizer); // Revised to handle multiple lines
     863                    }
     864                    if(command_element == null && (command_type.equals (StaticStrings.COLLECTIONMETADATA_PUBLIC_STR) || command_type.equals (StaticStrings.COLLECTIONMETADATA_CREATOR_STR) || command_type.equals (StaticStrings.COLLECTIONMETADATA_MAINTAINER_STR) || command_type.equals (StaticStrings.BUILDTYPE_STR))) {
     865                        command_element = parseMetadataSpecial (command_str);
     866                        // pre 2.71 hack
     867                        if (command_type.equals (StaticStrings.BUILDTYPE_STR)) {
     868                            build_types_parsed = true;
     869                        }
     870                    }
     871                    if(command_element == null && command_type.equals (StaticStrings.PLUGIN_STR)) {
     872                        command_element = parsePlugin (command_str);
     873                    }
     874                    // leave here for backwards compatibility
     875                    if(command_element == null && command_type.equals (StaticStrings.SEARCHTYPE_STR)) {
     876                        command_element = parseSearchType (command_str);
     877                        // pre 2.71 hack
     878                        search_types_parsed = true;
     879                       
     880                    }
     881                    if(command_element == null && command_type.equals (StaticStrings.SUBCOLLECTION_STR)) {
     882                        command_element = parseSubCollection (command_str);
     883                    }
     884                    if(command_element == null && command_type.equals (StaticStrings.SUBCOLLECTION_DEFAULT_INDEX_STR)) {
     885                        command_element = parseSubCollectionDefaultIndex (command_str);
     886                    }
     887                    if(command_element == null && command_type.equals (StaticStrings.SUBCOLLECTION_INDEX_STR)) {
     888                        command_element = parseSubCollectionIndex (command_str);
     889                    }
     890                    if(command_element == null && (command_type.equals (StaticStrings.SUPERCOLLECTION_STR) || command_type.equals (StaticStrings.CCS_STR))) {
     891                        command_element = parseSuperCollection (command_str);
     892                    }
     893                    // Doesn't match any known type
     894                    command_type = null;
     895                    if(command_element == null) {
     896                        // No-one knows what to do with this command, so we create an Unknown command element
     897                        command_element = document.createElement (StaticStrings.UNKNOWN_ELEMENT);
     898                        XMLTools.setValue (command_element, command_str);
     899                    }
     900                }
     901                // Or an empty line to remember for later
     902                else {
     903                    command_element = document.createElement (NEWLINE_ELEMENT);
     904                }
     905                // Now command element shouldn't be null so we append it to the collection config DOM, but only if we haven't been told not to add it
     906                //if(append_element) {
     907                collect_cfg_element.appendChild (command_element);
     908                //}
     909            }
     910            if (!build_types_parsed) {
     911                String buildtype_type = BuildTypeManager.BUILD_TYPE_MG;
     912                if (search_types_parsed) {
     913                    buildtype_type = BuildTypeManager.BUILD_TYPE_MGPP;
     914                }
     915                Element command_element = parseMetadataSpecial (StaticStrings.BUILDTYPE_STR+"  "+buildtype_type);
     916                Node target_node = findInsertionPoint (command_element);
     917                if(target_node != null) {
     918                    collect_cfg_element.insertBefore (command_element, target_node);
     919                }
     920                else {
     921                    collect_cfg_element.appendChild (command_element);
     922                }
     923               
     924            }
     925        }
     926        catch(Exception exception) {
     927            DebugStream.println ("Error in CollectionConfiguration.parse(java.io.File): " + exception);
     928            DebugStream.printStackTrace (exception);
     929        }
     930    }
     931   
     932    
     933    private Element parseClassify (String command_str) {
     934        Element command_element = null;
     935        try {
     936            CommandTokenizer tokenizer = new CommandTokenizer (command_str);
     937            // Check the token count. The token count from a command tokenizer isn't guarenteed to be correct, but it does give the maximum number of available tokens according to the underlying StringTokenizer (some of which may actually be append together by the CommandTokenizer as being a single argument).
     938            if(tokenizer.countTokens () >= 2) {  // Must support "classify Phind" (no args)
     939                command_element = document.createElement (StaticStrings.CLASSIFY_ELEMENT);
     940                // First token is classify
     941                tokenizer.nextToken ();
     942                // The next token is the classifier type
     943                command_element.setAttribute (StaticStrings.TYPE_ATTRIBUTE, tokenizer.nextToken ());
     944                // Now we parse out the remaining arguments into a hashmapping from name to value
     945                HashMap arguments = parseArguments (tokenizer);
     946                // Assign the arguments as Option elements, but watch out for the metadata argument as we treat that differently
     947                Iterator names = arguments.keySet ().iterator ();
     948                while(names.hasNext ()) {
     949                    String name = (String) names.next ();
     950                    String value = (String) arguments.get (name); // Can be null
     951                    // The metadata argument gets added as the content attribute
     952                    if (name.equals (StaticStrings.METADATA_ARGUMENT) && value != null) {
     953                        // Add the extracted namespace onto un-namespaced metadata names
     954                        StringTokenizer string_tokenizer = new StringTokenizer (value, ",");
     955                        value = "";
     956                        while (string_tokenizer.hasMoreElements ()) {
     957                            String token = (String) string_tokenizer.nextElement ();
     958                           
     959                            if (token.indexOf (StaticStrings.NS_SEP) == -1) {
     960                                token = StaticStrings.EXTRACTED_NAMESPACE + token;
     961                            }
     962                            else {
     963                                MetadataElement metadata_element = MetadataTools.getMetadataElementWithName (token);
     964                                if (metadata_element != null) {
     965                                    token = metadata_element.getDisplayName ();
     966                                }
     967                            }
     968                           
     969                            if (!value.equals ("")) {
     970                                value = value + ",";
     971                            }
     972                            value = value + token;
     973                        }
     974                    }
     975                    // Everything else is an Option Element
     976                    Element option_element = document.createElement (StaticStrings.OPTION_ELEMENT);
     977                    option_element.setAttribute (StaticStrings.NAME_ATTRIBUTE, name.substring (1));
     978                    if(value != null) {
     979                        // Remove any speech marks appended in strings containing whitespace
     980                        if(value.startsWith (StaticStrings.SPEECH_CHARACTER) && value.endsWith (StaticStrings.SPEECH_CHARACTER)) {
     981                            value = value.substring (1, value.length () - 1);
     982                        }
     983                        XMLTools.setValue (option_element, value);
     984                    }
     985                    option_element.setAttribute (StaticStrings.ASSIGNED_ATTRIBUTE, StaticStrings.TRUE_STR);
     986                    command_element.appendChild (option_element);
     987                    option_element = null;
     988                    name = null;
     989                    value = null;
     990                }
     991                names = null;
     992                arguments = null;
     993            }
     994            tokenizer = null;
     995        }
     996        catch(Exception error) {
     997        }
     998        return command_element;
     999    }
     1000   
     1001    private Element parseFormat (CommandTokenizer tokenizer) {
     1002        Element command_element = null;
     1003        try {
     1004            command_element = document.createElement (StaticStrings.FORMAT_ELEMENT);
     1005            String name_str = tokenizer.nextToken ();
     1006            String value_str = tokenizer.nextToken ();
     1007            if(name_str != null && value_str != null) {
     1008                command_element.setAttribute (StaticStrings.NAME_ATTRIBUTE, name_str);
     1009                // If the value is true or false we add it as an attribute
     1010                if(value_str.equalsIgnoreCase (StaticStrings.TRUE_STR) || value_str.equalsIgnoreCase (StaticStrings.FALSE_STR)) {
     1011                    command_element.setAttribute (StaticStrings.VALUE_ATTRIBUTE, value_str.toLowerCase ());
     1012                }
     1013                // Otherwise it gets added as a text node
     1014                else {
     1015                    // Ready the value str (which can contain all sorts of funky characters) for writing as a DOM value
     1016                    value_str = Codec.transform (value_str, Codec.GREENSTONE_TO_DOM);
     1017                    XMLTools.setValue (command_element, value_str);
     1018                }
     1019            }
     1020            else {
     1021                command_element = null;
     1022            }
     1023            name_str = null;
     1024            value_str = null;
     1025        }
     1026        catch (Exception exception) {
     1027            DebugStream.printStackTrace (exception);
     1028            command_element = null;
     1029        }
     1030        return command_element;
     1031    }
     1032   
     1033    private Element parseIndex (String command_str) {
     1034        Element command_element = null;
     1035        try {
     1036            StringTokenizer tokenizer = new StringTokenizer (command_str);
     1037            String command = tokenizer.nextToken ();
     1038            command_element = document.createElement (StaticStrings.INDEXES_ELEMENT);
     1039            command_element.setAttribute (StaticStrings.ASSIGNED_ATTRIBUTE, (command.equals (StaticStrings.INDEX_STR) ? StaticStrings.TRUE_STR : StaticStrings.FALSE_STR));
     1040            command = null;
     1041            if(!tokenizer.hasMoreTokens ()) {
     1042               
     1043                // there are no indexes
     1044                command_element.setAttribute (StaticStrings.ASSIGNED_ATTRIBUTE, StaticStrings.FALSE_STR);
     1045                command_element.setAttribute (StaticStrings.MGPP_ATTRIBUTE, StaticStrings.FALSE_STR); // for now
     1046                tokenizer = null;
     1047                return command_element;
     1048            }
     1049           
     1050            while(tokenizer.hasMoreTokens ()) {
     1051                Element index_element = document.createElement (StaticStrings.INDEX_ELEMENT);
     1052                String index_str = tokenizer.nextToken ();
     1053                // There are two types of index we have to consider. Old G2.38 and earlier use level:source tuplets while G2.39+ have just a single, non-comma separated list where order is important.
     1054                boolean old_index;
     1055                if(index_str.indexOf (StaticStrings.COLON_CHARACTER) != -1) {
     1056                    old_index = true;
     1057                    index_element.setAttribute (StaticStrings.LEVEL_ATTRIBUTE, index_str.substring (0, index_str.indexOf (StaticStrings.COLON_CHARACTER)));
     1058                    index_str = index_str.substring (index_str.indexOf (StaticStrings.COLON_CHARACTER) + 1);
     1059                    command_element.setAttribute (StaticStrings.MGPP_ATTRIBUTE, StaticStrings.FALSE_STR);
     1060                }
     1061                else {
     1062                    command_element.setAttribute (StaticStrings.MGPP_ATTRIBUTE, StaticStrings.TRUE_STR);
     1063                    old_index = false;
     1064                }
     1065                StringTokenizer content_tokenizer = new StringTokenizer (index_str, StaticStrings.COMMA_CHARACTER);
     1066                while(content_tokenizer.hasMoreTokens ()) {
     1067                    Element content_element = document.createElement (StaticStrings.CONTENT_ELEMENT);
     1068                    String content_str = content_tokenizer.nextToken ();
     1069                    // Since the contents of indexes have to be certain keywords, or metadata elements, if the content isn't a keyword and doesn't yet have a namespace, append the extracted metadata namespace.
     1070                    if(content_str.indexOf (StaticStrings.NS_SEP) == -1) {
     1071                        if(content_str.equals (StaticStrings.TEXT_STR) || (!old_index && content_str.equals (StaticStrings.ALLFIELDS_STR))) {
     1072                            // Our special strings are OK.
     1073                        }
     1074                        else {
     1075                            content_str = StaticStrings.EXTRACTED_NAMESPACE + content_str;
     1076                        }
     1077                    }
     1078                    content_element.setAttribute (StaticStrings.NAME_ATTRIBUTE, content_str);
     1079                    index_element.appendChild (content_element);
     1080                    content_element = null;
     1081                }
     1082                content_tokenizer = null;
     1083                index_str = null;
     1084                command_element.appendChild (index_element);
     1085                index_element = null;
     1086            }
     1087            tokenizer = null;
     1088        }
     1089        catch (Exception exception) {
     1090            exception.printStackTrace ();
     1091        }
     1092        return command_element;
     1093    }
     1094   
     1095    private Element parseIndexDefault (String command_str) {
     1096        Element command_element = null;
     1097        try {
     1098            StringTokenizer tokenizer = new StringTokenizer (command_str);
     1099            if(tokenizer.countTokens () >= 2) {
     1100                command_element = document.createElement (StaticStrings.INDEX_DEFAULT_ELEMENT);
     1101                command_element.setAttribute (StaticStrings.ASSIGNED_ATTRIBUTE, ((tokenizer.nextToken ()).equals (StaticStrings.INDEX_DEFAULT_STR) ? StaticStrings.TRUE_STR : StaticStrings.FALSE_STR));
     1102                String index_str = tokenizer.nextToken ();
    12061103                String level="";
    1207                 if (index_str.indexOf(StaticStrings.COLON_CHARACTER) !=-1){
    1208             level =  index_str.substring(0, index_str.indexOf(StaticStrings.COLON_CHARACTER));
    1209         }
    1210    
    1211         command_element.setAttribute(StaticStrings.LEVEL_ATTRIBUTE,level);
    1212                  
    1213         String content_str = index_str;
    1214                
    1215         if (index_str.indexOf(StaticStrings.COLON_CHARACTER) !=-1){
    1216             content_str = index_str.substring(index_str.indexOf(StaticStrings.COLON_CHARACTER) + 1);
    1217         }
    1218        
    1219         StringTokenizer content_tokenizer = new StringTokenizer(content_str, StaticStrings.COMMA_CHARACTER);
    1220         while(content_tokenizer.hasMoreTokens()) {
    1221             Element content_element = document.createElement(StaticStrings.CONTENT_ELEMENT);
    1222             content_element.setAttribute(StaticStrings.NAME_ATTRIBUTE, content_tokenizer.nextToken());
    1223             command_element.appendChild(content_element);
    1224             content_element = null;
    1225         }
    1226         content_tokenizer = null;
    1227         content_str = null;
    1228         content_str = null;
    1229         index_str = null;
    1230         }
    1231         tokenizer = null;
    1232     }
    1233     catch (Exception exception) {
    1234     }
    1235     return command_element;
    1236     }
    1237 
    1238     private Element parseLanguage(String command_str) {
    1239     Element command_element = null;
    1240     try {
    1241         StringTokenizer tokenizer = new StringTokenizer(command_str);
    1242         tokenizer.nextToken();
    1243         if(tokenizer.hasMoreTokens()) {
    1244         command_element = document.createElement(StaticStrings.LANGUAGES_ELEMENT);
    1245         while(tokenizer.hasMoreTokens()) {
    1246             Element language_element = document.createElement(StaticStrings.LANGUAGE_ELEMENT);
    1247             language_element.setAttribute(StaticStrings.NAME_ATTRIBUTE, tokenizer.nextToken());
    1248             command_element.appendChild(language_element);
    1249             language_element = null;
    1250         }
    1251         }
    1252         tokenizer = null;
    1253     }
    1254     catch (Exception exception) {
    1255     }
    1256     return command_element;
    1257     }
    1258 
    1259     private Element parseLanguageDefault(String command_str) {
    1260     Element command_element = null;
    1261     try {
    1262         StringTokenizer tokenizer = new StringTokenizer(command_str);
    1263         if(tokenizer.countTokens() >= 2) {
    1264         command_element = document.createElement(StaticStrings.LANGUAGE_DEFAULT_ELEMENT);
    1265         tokenizer.nextToken();
    1266         String default_language_str = tokenizer.nextToken();
    1267         command_element.setAttribute(StaticStrings.NAME_ATTRIBUTE, default_language_str);
    1268         command_element.setAttribute(StaticStrings.ASSIGNED_ATTRIBUTE, StaticStrings.TRUE_STR);
    1269         default_language_str = null;
    1270         }
    1271         tokenizer = null;
    1272     }
    1273     catch (Exception exception) {
    1274     }
    1275     return command_element;
    1276     }
    1277 
    1278     private Element parseLanguageMetadata(String command_str) {
    1279     Element command_element = null;
    1280     try {
    1281         StringTokenizer tokenizer = new StringTokenizer(command_str);
    1282         if(tokenizer.countTokens() >= 2) {
    1283         command_element = document.createElement(StaticStrings.LANGUAGE_METADATA_ELEMENT);
    1284         tokenizer.nextToken();
    1285         String language_metadata_str = tokenizer.nextToken();
    1286         if (language_metadata_str.indexOf(StaticStrings.NS_SEP) == -1) {
    1287             language_metadata_str = StaticStrings.EXTRACTED_NAMESPACE + language_metadata_str;
    1288         }
    1289         command_element.setAttribute(StaticStrings.NAME_ATTRIBUTE, language_metadata_str);
    1290         command_element.setAttribute(StaticStrings.ASSIGNED_ATTRIBUTE, StaticStrings.TRUE_STR);
    1291         language_metadata_str = null;
    1292         }
    1293         tokenizer = null;
    1294        
    1295     }
    1296     catch (Exception exception) {
    1297     }
    1298     return command_element;
    1299     }
    1300    
    1301     private Element parseIndexOptions(String command_str, String type, boolean assigned) {
    1302     Element command_element = null;
    1303     try {
    1304         StringTokenizer tokenizer = new StringTokenizer(command_str);
    1305         // First token is command type
    1306         String command = tokenizer.nextToken();
    1307         if(tokenizer.hasMoreTokens()) {
    1308         command_element = document.createElement(StaticStrings.INDEXOPTIONS_ELEMENT);
    1309         command_element.setAttribute(StaticStrings.NAME_ATTRIBUTE,type);
    1310         command_element.setAttribute(StaticStrings.ASSIGNED_ATTRIBUTE, (assigned ? StaticStrings.TRUE_STR : StaticStrings.FALSE_STR));
    1311         while(tokenizer.hasMoreTokens()) {
    1312             Element option_element = document.createElement(StaticStrings.INDEXOPTION_ELEMENT);
    1313             option_element.setAttribute(StaticStrings.NAME_ATTRIBUTE, tokenizer.nextToken());
    1314             command_element.appendChild(option_element);
    1315             option_element = null;
    1316         }
    1317         }
    1318         command = null;
    1319     }
    1320     catch(Exception exception) {
    1321     }
    1322     return command_element;
    1323     }
    1324 
    1325     private Element parseIndexOptionDefault(String command_str, String type, boolean assigned) {
    1326     Element command_element = null;
    1327     try {
    1328         StringTokenizer tokenizer = new StringTokenizer(command_str);
    1329         // First token is command type
    1330         String command = tokenizer.nextToken();
    1331         if(tokenizer.hasMoreTokens()) {
    1332         command_element = document.createElement(StaticStrings.INDEXOPTION_DEFAULT_ELEMENT);
    1333         command_element.setAttribute(StaticStrings.ASSIGNED_ATTRIBUTE, (assigned ? StaticStrings.TRUE_STR : StaticStrings.FALSE_STR)); // is it commented out or not?
    1334         command_element.setAttribute(StaticStrings.NAME_ATTRIBUTE, type);
    1335         command_element.setAttribute(StaticStrings.VALUE_ATTRIBUTE, tokenizer.nextToken());
    1336         }
    1337        
    1338         tokenizer = null;
    1339     }
    1340     catch (Exception exception) {
    1341     }
    1342     return command_element;
    1343     }
    1344 
    1345     private Element parseMetadata(CommandTokenizer tokenizer) {
    1346     Element command_element = null;
    1347     try {
    1348         command_element = document.createElement(StaticStrings.COLLECTIONMETADATA_ELEMENT);
    1349         String name_str = tokenizer.nextToken();
    1350         String value_str = tokenizer.nextToken();
    1351         if(name_str != null && value_str != null) {
    1352         String language_str = Configuration.getLanguage();
    1353         // Check if the value string is actually a language string
    1354         if(value_str.startsWith(StaticStrings.LBRACKET_CHARACTER) && value_str.endsWith(StaticStrings.RBRACKET_CHARACTER)) {
    1355             language_str = value_str.substring(value_str.indexOf(StaticStrings.LANGUAGE_ARGUMENT) + 2, value_str.length() - 1);
    1356             value_str = tokenizer.nextToken();
    1357         }
    1358         if(value_str != null) {
    1359             // Ready the value str (which can contain all sorts of funky characters) for writing as a DOM value
    1360             value_str = Codec.transform(value_str, Codec.GREENSTONE_TO_DOM);
    1361             command_element.setAttribute(StaticStrings.NAME_ATTRIBUTE, name_str);
    1362             command_element.setAttribute(StaticStrings.LANGUAGE_ATTRIBUTE, language_str);
    1363             command_element.setAttribute(StaticStrings.ASSIGNED_ATTRIBUTE, StaticStrings.TRUE_STR);
    1364             XMLTools.setValue(command_element, value_str);
    1365         }
    1366         else {
    1367             command_element = null;
    1368         }
    1369         language_str = null;
    1370         }
    1371         else {
    1372         command_element = null;
    1373         }
    1374         name_str = null;
    1375         value_str = null;
    1376     }
    1377     catch (Exception exception) {
    1378         DebugStream.printStackTrace(exception);
    1379         command_element = null;
    1380     }
    1381     return command_element;
    1382     }
    1383 
    1384     private Element parseMetadataSpecial(String command_str) {
    1385     Element command_element = null;
    1386     try {
    1387         StringTokenizer tokenizer = new StringTokenizer(command_str);
    1388         if(tokenizer.countTokens() >= 2) {
    1389         String name_str = tokenizer.nextToken();
    1390         String value_str = tokenizer.nextToken();
    1391         if (name_str.equals(StaticStrings.COLLECTIONMETADATA_CREATOR_STR)) {
    1392             command_element = document.createElement(StaticStrings.COLLECTIONMETADATA_CREATOR_ELEMENT);
    1393         }
    1394         else if(name_str.equals(StaticStrings.COLLECTIONMETADATA_MAINTAINER_STR)) {
    1395             command_element = document.createElement(StaticStrings.COLLECTIONMETADATA_MAINTAINER_ELEMENT);
    1396         }
    1397         else if(name_str.equals(StaticStrings.COLLECTIONMETADATA_PUBLIC_STR)) {
    1398             command_element = document.createElement(StaticStrings.COLLECTIONMETADATA_PUBLIC_ELEMENT);
    1399         }
    1400         else if (name_str.equals(StaticStrings.BUILDTYPE_STR)) {
    1401             command_element = document.createElement(StaticStrings.BUILDTYPE_ELEMENT);
    1402         }
    1403         if(command_element != null) {
    1404             command_element.setAttribute(StaticStrings.NAME_ATTRIBUTE, name_str);
    1405             command_element.setAttribute(StaticStrings.LANGUAGE_ATTRIBUTE, StaticStrings.ENGLISH_LANGUAGE_STR);
    1406             command_element.setAttribute(StaticStrings.SPECIAL_ATTRIBUTE, StaticStrings.TRUE_STR);
    1407             command_element.setAttribute(StaticStrings.ASSIGNED_ATTRIBUTE, StaticStrings.TRUE_STR);
    1408             if(value_str.startsWith(StaticStrings.SPEECH_CHARACTER) && value_str.endsWith(StaticStrings.SPEECH_CHARACTER)) {
    1409             value_str = value_str.substring(1, value_str.length() - 1);
    1410             }
    1411             XMLTools.setValue(command_element, value_str);
    1412         }
    1413         value_str = null;
    1414         name_str = null;
    1415         }
    1416         tokenizer = null;
    1417     }
    1418     catch (Exception exception) {
    1419     }
    1420     return command_element;
    1421     }
    1422 
    1423     private Element parsePlugin(String command_str) {
    1424     Element command_element = null;
    1425     try {
    1426         CommandTokenizer tokenizer = new CommandTokenizer(command_str);
    1427         // Check the token count. The token count from a command tokenizer isn't guarenteed to be correct, but it does give the maximum number of available tokens according to the underlying StringTokenizer (some of which may actually be append together by the CommandTokenizer as being a single argument).
    1428         if(tokenizer.countTokens() >= 2) {
    1429         command_element = document.createElement(StaticStrings.PLUGIN_ELEMENT);
    1430         // First token is plugin
    1431         tokenizer.nextToken();
    1432         // The next token is the type
    1433         String type = tokenizer.nextToken();
    1434         command_element.setAttribute(StaticStrings.TYPE_ATTRIBUTE, type);
    1435         // Now we parse out the remaining arguments into a hashmapping from name to value
    1436         HashMap arguments = parseArguments(tokenizer);
    1437         // Assign the arguments as Option elements, but watch out for the metadata argument as we treat that differently
    1438         // also watch out for the deprecated -use_metadata_files option to RecPlug and remove it
    1439         Iterator names = arguments.keySet().iterator();
    1440         while(names.hasNext()) {
    1441             String name = (String) names.next();
    1442             String value = (String) arguments.get(name); // Can be null
    1443            
    1444             if(type.equals(StaticStrings.RECPLUG_STR) && name.substring(1).equals(StaticStrings.USE_METADATA_FILES_ARGUMENT)) {
    1445             continue; // ignore this option
    1446             }
    1447             Element option_element = document.createElement(StaticStrings.OPTION_ELEMENT);
    1448             option_element.setAttribute(StaticStrings.NAME_ATTRIBUTE, name.substring(1));
    1449             option_element.setAttribute(StaticStrings.ASSIGNED_ATTRIBUTE, StaticStrings.TRUE_STR);
    1450             if(value != null) {
    1451             // Remove any speech marks appended in strings containing whitespace
    1452             if(value.startsWith(StaticStrings.SPEECH_CHARACTER) && value.endsWith(StaticStrings.SPEECH_CHARACTER)) {
    1453                 value = value.substring(1, value.length() - 1);
    1454             }
    1455             if(name.equals(StaticStrings.METADATA_ARGUMENT)) {
    1456                 // The metadata argument must be the fully qualified name of a metadata element, so if it doesn't yet have a namespace, append the extracted metadata namespace.
    1457                 if(value.indexOf(StaticStrings.NS_SEP) == -1) {
    1458                 value = StaticStrings.EXTRACTED_NAMESPACE + value;
    1459                 }
    1460             }
    1461             XMLTools.setValue(option_element, value);
    1462             }
    1463             command_element.appendChild(option_element);
    1464             option_element = null;
    1465             name = null;
    1466             value = null;
    1467         }
    1468 
    1469         type = null;
    1470         names = null;
    1471         arguments = null;
    1472         }
    1473         tokenizer = null;
    1474     }
    1475     catch(Exception exception) {
    1476     }
    1477     return command_element;
    1478     }
    1479 
     1104                if (index_str.indexOf (StaticStrings.COLON_CHARACTER) !=-1) {
     1105                    level =  index_str.substring (0, index_str.indexOf (StaticStrings.COLON_CHARACTER));
     1106                }
     1107                
     1108                command_element.setAttribute (StaticStrings.LEVEL_ATTRIBUTE,level);
     1109               
     1110                String content_str = index_str;
     1111               
     1112                if (index_str.indexOf (StaticStrings.COLON_CHARACTER) !=-1) {
     1113                    content_str = index_str.substring (index_str.indexOf (StaticStrings.COLON_CHARACTER) + 1);
     1114                }
     1115               
     1116                StringTokenizer content_tokenizer = new StringTokenizer (content_str, StaticStrings.COMMA_CHARACTER);
     1117                while(content_tokenizer.hasMoreTokens ()) {
     1118                    Element content_element = document.createElement (StaticStrings.CONTENT_ELEMENT);
     1119                    content_element.setAttribute (StaticStrings.NAME_ATTRIBUTE, content_tokenizer.nextToken ());
     1120                    command_element.appendChild (content_element);
     1121                    content_element = null;
     1122                }
     1123                content_tokenizer = null;
     1124                content_str = null;
     1125                content_str = null;
     1126                index_str = null;
     1127            }
     1128            tokenizer = null;
     1129        }
     1130        catch (Exception exception) {
     1131        }
     1132        return command_element;
     1133    }
     1134   
     1135    private Element parseLanguage (String command_str) {
     1136        Element command_element = null;
     1137        try {
     1138            StringTokenizer tokenizer = new StringTokenizer (command_str);
     1139            tokenizer.nextToken ();
     1140            if(tokenizer.hasMoreTokens ()) {
     1141                command_element = document.createElement (StaticStrings.LANGUAGES_ELEMENT);
     1142                while(tokenizer.hasMoreTokens ()) {
     1143                    Element language_element = document.createElement (StaticStrings.LANGUAGE_ELEMENT);
     1144                    language_element.setAttribute (StaticStrings.NAME_ATTRIBUTE, tokenizer.nextToken ());
     1145                    command_element.appendChild (language_element);
     1146                    language_element = null;
     1147                }
     1148            }
     1149            tokenizer = null;
     1150        }
     1151        catch (Exception exception) {
     1152        }
     1153        return command_element;
     1154    }
     1155   
     1156    private Element parseLanguageDefault (String command_str) {
     1157        Element command_element = null;
     1158        try {
     1159            StringTokenizer tokenizer = new StringTokenizer (command_str);
     1160            if(tokenizer.countTokens () >= 2) {
     1161                command_element = document.createElement (StaticStrings.LANGUAGE_DEFAULT_ELEMENT);
     1162                tokenizer.nextToken ();
     1163                String default_language_str = tokenizer.nextToken ();
     1164                command_element.setAttribute (StaticStrings.NAME_ATTRIBUTE, default_language_str);
     1165                command_element.setAttribute (StaticStrings.ASSIGNED_ATTRIBUTE, StaticStrings.TRUE_STR);
     1166                default_language_str = null;
     1167            }
     1168            tokenizer = null;
     1169        }
     1170        catch (Exception exception) {
     1171        }
     1172        return command_element;
     1173    }
     1174   
     1175    private Element parseLanguageMetadata (String command_str) {
     1176        Element command_element = null;
     1177        try {
     1178            StringTokenizer tokenizer = new StringTokenizer (command_str);
     1179            if(tokenizer.countTokens () >= 2) {
     1180                command_element = document.createElement (StaticStrings.LANGUAGE_METADATA_ELEMENT);
     1181                tokenizer.nextToken ();
     1182                String language_metadata_str = tokenizer.nextToken ();
     1183                if (language_metadata_str.indexOf (StaticStrings.NS_SEP) == -1) {
     1184                    language_metadata_str = StaticStrings.EXTRACTED_NAMESPACE + language_metadata_str;
     1185                }
     1186                command_element.setAttribute (StaticStrings.NAME_ATTRIBUTE, language_metadata_str);
     1187                command_element.setAttribute (StaticStrings.ASSIGNED_ATTRIBUTE, StaticStrings.TRUE_STR);
     1188                language_metadata_str = null;
     1189            }
     1190            tokenizer = null;
     1191           
     1192        }
     1193        catch (Exception exception) {
     1194        }
     1195        return command_element;
     1196    }
     1197   
     1198    private Element parseIndexOptions (String command_str, String type, boolean assigned) {
     1199        Element command_element = null;
     1200        try {
     1201            StringTokenizer tokenizer = new StringTokenizer (command_str);
     1202            // First token is command type
     1203            String command = tokenizer.nextToken ();
     1204            if(tokenizer.hasMoreTokens ()) {
     1205                command_element = document.createElement (StaticStrings.INDEXOPTIONS_ELEMENT);
     1206                command_element.setAttribute (StaticStrings.NAME_ATTRIBUTE,type);
     1207                command_element.setAttribute (StaticStrings.ASSIGNED_ATTRIBUTE, (assigned ? StaticStrings.TRUE_STR : StaticStrings.FALSE_STR));
     1208                while(tokenizer.hasMoreTokens ()) {
     1209                    Element option_element = document.createElement (StaticStrings.INDEXOPTION_ELEMENT);
     1210                    option_element.setAttribute (StaticStrings.NAME_ATTRIBUTE, tokenizer.nextToken ());
     1211                    command_element.appendChild (option_element);
     1212                    option_element = null;
     1213                }
     1214            }
     1215            command = null;
     1216        }
     1217        catch(Exception exception) {
     1218        }
     1219        return command_element;
     1220    }
     1221   
     1222    private Element parseIndexOptionDefault (String command_str, String type, boolean assigned) {
     1223        Element command_element = null;
     1224        try {
     1225            StringTokenizer tokenizer = new StringTokenizer (command_str);
     1226            // First token is command type
     1227            String command = tokenizer.nextToken ();
     1228            if(tokenizer.hasMoreTokens ()) {
     1229                command_element = document.createElement (StaticStrings.INDEXOPTION_DEFAULT_ELEMENT);
     1230                command_element.setAttribute (StaticStrings.ASSIGNED_ATTRIBUTE, (assigned ? StaticStrings.TRUE_STR : StaticStrings.FALSE_STR)); // is it commented out or not?
     1231                command_element.setAttribute (StaticStrings.NAME_ATTRIBUTE, type);
     1232                command_element.setAttribute (StaticStrings.VALUE_ATTRIBUTE, tokenizer.nextToken ());
     1233            }
     1234           
     1235            tokenizer = null;
     1236        }
     1237        catch (Exception exception) {
     1238        }
     1239        return command_element;
     1240    }
     1241   
     1242    private Element parseMetadata (CommandTokenizer tokenizer) {
     1243        Element command_element = null;
     1244        try {
     1245            command_element = document.createElement (StaticStrings.COLLECTIONMETADATA_ELEMENT);
     1246            String name_str = tokenizer.nextToken ();
     1247            String value_str = tokenizer.nextToken ();
     1248            if(name_str != null && value_str != null) {
     1249                String language_str = Configuration.getLanguage ();
     1250                // Check if the value string is actually a language string
     1251                if(value_str.startsWith (StaticStrings.LBRACKET_CHARACTER) && value_str.endsWith (StaticStrings.RBRACKET_CHARACTER)) {
     1252                    language_str = value_str.substring (value_str.indexOf (StaticStrings.LANGUAGE_ARGUMENT) + 2, value_str.length () - 1);
     1253                    value_str = tokenizer.nextToken ();
     1254                }
     1255                if(value_str != null) {
     1256                    // Ready the value str (which can contain all sorts of funky characters) for writing as a DOM value
     1257                    value_str = Codec.transform (value_str, Codec.GREENSTONE_TO_DOM);
     1258                    command_element.setAttribute (StaticStrings.NAME_ATTRIBUTE, name_str);
     1259                    command_element.setAttribute (StaticStrings.LANGUAGE_ATTRIBUTE, language_str);
     1260                    command_element.setAttribute (StaticStrings.ASSIGNED_ATTRIBUTE, StaticStrings.TRUE_STR);
     1261                    XMLTools.setValue (command_element, value_str);
     1262                }
     1263                else {
     1264                    command_element = null;
     1265                }
     1266                language_str = null;
     1267            }
     1268            else {
     1269                command_element = null;
     1270            }
     1271            name_str = null;
     1272            value_str = null;
     1273        }
     1274        catch (Exception exception) {
     1275            DebugStream.printStackTrace (exception);
     1276            command_element = null;
     1277        }
     1278        return command_element;
     1279    }
     1280   
     1281    private Element parseMetadataSpecial (String command_str) {
     1282        Element command_element = null;
     1283        try {
     1284            StringTokenizer tokenizer = new StringTokenizer (command_str);
     1285            if(tokenizer.countTokens () >= 2) {
     1286                String name_str = tokenizer.nextToken ();
     1287                String value_str = tokenizer.nextToken ();
     1288                if (name_str.equals (StaticStrings.COLLECTIONMETADATA_CREATOR_STR)) {
     1289                    command_element = document.createElement (StaticStrings.COLLECTIONMETADATA_CREATOR_ELEMENT);
     1290                }
     1291                else if(name_str.equals (StaticStrings.COLLECTIONMETADATA_MAINTAINER_STR)) {
     1292                    command_element = document.createElement (StaticStrings.COLLECTIONMETADATA_MAINTAINER_ELEMENT);
     1293                }
     1294                else if(name_str.equals (StaticStrings.COLLECTIONMETADATA_PUBLIC_STR)) {
     1295                    command_element = document.createElement (StaticStrings.COLLECTIONMETADATA_PUBLIC_ELEMENT);
     1296                }
     1297                else if (name_str.equals (StaticStrings.BUILDTYPE_STR)) {
     1298                    command_element = document.createElement (StaticStrings.BUILDTYPE_ELEMENT);
     1299                }
     1300                if(command_element != null) {
     1301                    command_element.setAttribute (StaticStrings.NAME_ATTRIBUTE, name_str);
     1302                    command_element.setAttribute (StaticStrings.LANGUAGE_ATTRIBUTE, StaticStrings.ENGLISH_LANGUAGE_STR);
     1303                    command_element.setAttribute (StaticStrings.SPECIAL_ATTRIBUTE, StaticStrings.TRUE_STR);
     1304                    command_element.setAttribute (StaticStrings.ASSIGNED_ATTRIBUTE, StaticStrings.TRUE_STR);
     1305                    if(value_str.startsWith (StaticStrings.SPEECH_CHARACTER) && value_str.endsWith (StaticStrings.SPEECH_CHARACTER)) {
     1306                        value_str = value_str.substring (1, value_str.length () - 1);
     1307                    }
     1308                    XMLTools.setValue (command_element, value_str);
     1309                }
     1310                value_str = null;
     1311                name_str = null;
     1312            }
     1313            tokenizer = null;
     1314        }
     1315        catch (Exception exception) {
     1316        }
     1317        return command_element;
     1318    }
     1319   
     1320    private Element parsePlugin (String command_str) {
     1321        Element command_element = null;
     1322        try {
     1323            CommandTokenizer tokenizer = new CommandTokenizer (command_str);
     1324            // Check the token count. The token count from a command tokenizer isn't guarenteed to be correct, but it does give the maximum number of available tokens according to the underlying StringTokenizer (some of which may actually be append together by the CommandTokenizer as being a single argument).
     1325            if(tokenizer.countTokens () >= 2) {
     1326                command_element = document.createElement (StaticStrings.PLUGIN_ELEMENT);
     1327                // First token is plugin
     1328                tokenizer.nextToken ();
     1329                // The next token is the type
     1330                String type = tokenizer.nextToken ();
     1331                command_element.setAttribute (StaticStrings.TYPE_ATTRIBUTE, type);
     1332                // Now we parse out the remaining arguments into a hashmapping from name to value
     1333                HashMap arguments = parseArguments (tokenizer);
     1334                // Assign the arguments as Option elements, but watch out for the metadata argument as we treat that differently
     1335                // also watch out for the deprecated -use_metadata_files option to RecPlug and remove it
     1336                Iterator names = arguments.keySet ().iterator ();
     1337                while(names.hasNext ()) {
     1338                    String name = (String) names.next ();
     1339                    String value = (String) arguments.get (name); // Can be null
     1340                   
     1341                    if(type.equals (StaticStrings.RECPLUG_STR) && name.substring (1).equals (StaticStrings.USE_METADATA_FILES_ARGUMENT)) {
     1342                        continue; // ignore this option
     1343                    }
     1344                    Element option_element = document.createElement (StaticStrings.OPTION_ELEMENT);
     1345                    option_element.setAttribute (StaticStrings.NAME_ATTRIBUTE, name.substring (1));
     1346                    option_element.setAttribute (StaticStrings.ASSIGNED_ATTRIBUTE, StaticStrings.TRUE_STR);
     1347                    if(value != null) {
     1348                        // Remove any speech marks appended in strings containing whitespace
     1349                        if(value.startsWith (StaticStrings.SPEECH_CHARACTER) && value.endsWith (StaticStrings.SPEECH_CHARACTER)) {
     1350                            value = value.substring (1, value.length () - 1);
     1351                        }
     1352                        if(name.equals (StaticStrings.METADATA_ARGUMENT)) {
     1353                            // The metadata argument must be the fully qualified name of a metadata element, so if it doesn't yet have a namespace, append the extracted metadata namespace.
     1354                            if(value.indexOf (StaticStrings.NS_SEP) == -1) {
     1355                                value = StaticStrings.EXTRACTED_NAMESPACE + value;
     1356                            }
     1357                        }
     1358                        XMLTools.setValue (option_element, value);
     1359                    }
     1360                    command_element.appendChild (option_element);
     1361                    option_element = null;
     1362                    name = null;
     1363                    value = null;
     1364                }
     1365               
     1366                type = null;
     1367                names = null;
     1368                arguments = null;
     1369            }
     1370            tokenizer = null;
     1371        }
     1372        catch(Exception exception) {
     1373        }
     1374        return command_element;
     1375    }
     1376   
    14801377    /* search types are now handled as formats - leave this here to convert in case we have an old config file */
    1481     private Element parseSearchType(String command_str) {
    1482     Element command_element = null;
    1483     try {
    1484         StringTokenizer tokenizer = new StringTokenizer(command_str);
    1485         // First token is command type (searchtype)
    1486         tokenizer.nextToken();
    1487         if(tokenizer.hasMoreTokens()) {
    1488         command_element = document.createElement(StaticStrings.FORMAT_ELEMENT);
    1489         command_element.setAttribute(StaticStrings.NAME_ATTRIBUTE, "SearchTypes");
    1490         String value = tokenizer.nextToken();
    1491         while(tokenizer.hasMoreTokens()) {
    1492             value += ","+tokenizer.nextToken();
    1493         }
    1494         value = Codec.transform(value, Codec.GREENSTONE_TO_DOM);
    1495         XMLTools.setValue(command_element, value);     
    1496         }
    1497     }
    1498     catch(Exception exception) {
    1499     }
    1500     return command_element;
    1501     }
    1502 
    1503     private Element parseSubCollection(String command_str) {
    1504     Element command_element = null;
    1505     try {
    1506         CommandTokenizer tokenizer = new CommandTokenizer(command_str);
    1507         if(tokenizer.countTokens() >= 3) {
    1508         command_element = document.createElement(StaticStrings.SUBCOLLECTION_ELEMENT);
    1509         // First token is command type
    1510         tokenizer.nextToken();
    1511         // Then subcollection identifier
    1512         command_element.setAttribute(StaticStrings.NAME_ATTRIBUTE, tokenizer.nextToken());
    1513         // Then finally the pattern used to build the subcollection partition
    1514         String full_pattern_str = tokenizer.nextToken();
    1515         // Set inclusion/exclusion flag and remove any exclamation mark
    1516         boolean exclusion = full_pattern_str.startsWith(StaticStrings.EXCLAMATION_CHARACTER);
    1517         if (exclusion) {
    1518             full_pattern_str = full_pattern_str.substring(1, full_pattern_str.length());
    1519             command_element.setAttribute(StaticStrings.TYPE_ATTRIBUTE, StaticStrings.EXCLUDE_STR);
    1520         }
    1521         else {
    1522             command_element.setAttribute(StaticStrings.TYPE_ATTRIBUTE, StaticStrings.INCLUDE_STR);
    1523         }
    1524         StringTokenizer pattern_tokenizer = new StringTokenizer(full_pattern_str, StaticStrings.SEPARATOR_CHARACTER);
    1525         if(pattern_tokenizer.countTokens() >= 2) {
    1526             String content_str = pattern_tokenizer.nextToken();
    1527             // Since the contents of indexes have to be certain keywords, or metadata elements, if the content isn't a keyword and doesn't yet have a namespace, append the extracted metadata namespace.
    1528             if(!content_str.equals(StaticStrings.FILENAME_STR) && content_str.indexOf(StaticStrings.NS_SEP) == -1) {
    1529             content_str = StaticStrings.EXTRACTED_NAMESPACE + content_str;
    1530             }
    1531             command_element.setAttribute(StaticStrings.CONTENT_ATTRIBUTE, content_str);
    1532             XMLTools.setValue(command_element, pattern_tokenizer.nextToken());
    1533             if(pattern_tokenizer.hasMoreTokens()) {
    1534             command_element.setAttribute(StaticStrings.OPTIONS_ATTRIBUTE, pattern_tokenizer.nextToken());
    1535             }
    1536         }
    1537         pattern_tokenizer = null;
    1538         }
    1539     }
    1540     catch(Exception exception) {
    1541         exception.printStackTrace();
    1542     }
    1543     return command_element;
    1544     }
    1545 
    1546     private Element parseSubCollectionDefaultIndex(String command_str) {
    1547     Element command_element = null;
    1548     try {
    1549         StringTokenizer tokenizer = new StringTokenizer(command_str);
    1550         if(tokenizer.countTokens() == 2) {
    1551         command_element = document.createElement(StaticStrings.SUBCOLLECTION_DEFAULT_INDEX_ELEMENT);
    1552         tokenizer.nextToken();
    1553         //command_element.setAttribute(CONTENT_ATTRIBUTE, tokenizer.nextToken());
    1554         String content_str = tokenizer.nextToken();
    1555         StringTokenizer content_tokenizer = new StringTokenizer(content_str, StaticStrings.COMMA_CHARACTER);
    1556         while(content_tokenizer.hasMoreTokens()) {
    1557             Element content_element = document.createElement(StaticStrings.CONTENT_ELEMENT);
    1558             content_element.setAttribute(StaticStrings.NAME_ATTRIBUTE, content_tokenizer.nextToken());
    1559             command_element.appendChild(content_element);
    1560             content_element = null;
    1561         }
    1562         content_tokenizer = null;
    1563         content_str = null;
    1564         }
    1565         tokenizer = null;
    1566     }
    1567     catch(Exception exception) {
    1568     }
    1569     return command_element;
    1570     }
    1571 
    1572     private Element parseSubCollectionIndex(String command_str) {
    1573     Element command_element = null;
    1574     try {
    1575         StringTokenizer tokenizer = new StringTokenizer(command_str);
    1576         tokenizer.nextToken();
    1577         if(tokenizer.hasMoreTokens()) {
    1578         command_element = document.createElement(StaticStrings.SUBCOLLECTION_INDEXES_ELEMENT);
    1579         }
    1580         while(tokenizer.hasMoreTokens()) {
    1581         Element subcollectionindex_element = document.createElement(StaticStrings.INDEX_ELEMENT);
    1582         //command_element.setAttribute(CONTENT_ATTRIBUTE, tokenizer.nextToken());
    1583         String content_str = tokenizer.nextToken();
    1584         StringTokenizer content_tokenizer = new StringTokenizer(content_str, StaticStrings.COMMA_CHARACTER);
    1585         while(content_tokenizer.hasMoreTokens()) {
    1586             Element content_element = document.createElement(StaticStrings.CONTENT_ELEMENT);
    1587             content_element.setAttribute(StaticStrings.NAME_ATTRIBUTE, content_tokenizer.nextToken());
    1588             subcollectionindex_element.appendChild(content_element);
    1589             content_element = null;
    1590         }
    1591         content_tokenizer = null;
    1592         content_str = null;
    1593         command_element.appendChild(subcollectionindex_element);
    1594         subcollectionindex_element = null;
    1595         }
    1596         tokenizer = null;
    1597     }
    1598     catch (Exception exception) {
    1599     }
    1600     return command_element;
    1601     }
    1602 
    1603     private Element parseSuperCollection(String command_str) {
    1604     Element command_element = null;
    1605     try {
    1606         StringTokenizer tokenizer = new StringTokenizer(command_str);
    1607         if(tokenizer.countTokens() >= 3) {
    1608         command_element = document.createElement(StaticStrings.SUPERCOLLECTION_ELEMENT);
    1609         tokenizer.nextToken();
    1610         while(tokenizer.hasMoreTokens()) {
    1611             Element collection_element = document.createElement(StaticStrings.COLLECTION_ELEMENT);
    1612             collection_element.setAttribute(StaticStrings.NAME_ATTRIBUTE, tokenizer.nextToken());
    1613             command_element.appendChild(collection_element);
    1614             collection_element = null;
    1615         }
    1616         }
    1617         tokenizer = null;
    1618     }
    1619     catch(Exception exception) {
    1620     }
    1621     return command_element;
    1622     }
    1623 
    1624     static private String pluginToString(Element command_element, boolean show_extracted_namespace) {
    1625     StringBuffer text = new StringBuffer();
    1626     if(!command_element.getAttribute(StaticStrings.SEPARATOR_ATTRIBUTE).equals(StaticStrings.TRUE_STR)) {
    1627         text.append(StaticStrings.PLUGIN_STR);
    1628         text.append(StaticStrings.TAB_CHARACTER);
    1629         text.append(StaticStrings.TAB_CHARACTER);
    1630         text.append(command_element.getAttribute(StaticStrings.TYPE_ATTRIBUTE));
    1631         // Retrieve, and output, the arguments
    1632         NodeList option_elements = command_element.getElementsByTagName(StaticStrings.OPTION_ELEMENT);
    1633         int option_elements_length = option_elements.getLength();
    1634         if(option_elements_length > 0) {
    1635         for(int j = 0; j < option_elements_length; j++) {
    1636             Element option_element = (Element) option_elements.item(j);
    1637             if(option_element.getAttribute(StaticStrings.ASSIGNED_ATTRIBUTE).equals(StaticStrings.TRUE_STR)) {
    1638             text.append(StaticStrings.SPACE_CHARACTER);
    1639             text.append(StaticStrings.MINUS_CHARACTER);
    1640             text.append(option_element.getAttribute(StaticStrings.NAME_ATTRIBUTE));
    1641             String value_str = XMLTools.getValue(option_element);
    1642             if(!show_extracted_namespace && value_str.startsWith(StaticStrings.EXTRACTED_NAMESPACE)) {
    1643                 value_str = value_str.substring(StaticStrings.EXTRACTED_NAMESPACE.length());
    1644             }
    1645             if(value_str.length() > 0) {
    1646                 text.append(StaticStrings.SPACE_CHARACTER);
    1647                 if(value_str.indexOf(StaticStrings.SPACE_CHARACTER) == -1) {
    1648                 text.append(value_str);
    1649                 }
    1650                 else {
    1651                 text.append(StaticStrings.SPEECH_CHARACTER);
    1652                 text.append(value_str);
    1653                 text.append(StaticStrings.SPEECH_CHARACTER);
    1654                 }
    1655             }
    1656             value_str = null;
    1657             }
    1658             option_element = null;
    1659         }
    1660         }
    1661         option_elements = null;
    1662     }
    1663     return text.toString();
    1664     }
    1665 
    1666     static private String searchtypeToString(Element command_element) {
    1667     if(command_element.getAttribute(StaticStrings.ASSIGNED_ATTRIBUTE).equals(StaticStrings.TRUE_STR)) {
    1668         StringBuffer text = new StringBuffer(StaticStrings.SEARCHTYPE_STR);
    1669         text.append(StaticStrings.TAB_CHARACTER);
    1670         NodeList search_elements = command_element.getElementsByTagName(StaticStrings.CONTENT_ELEMENT);
    1671         int search_elements_length = search_elements.getLength();
    1672         for(int i = 0; i < search_elements_length; i++) {
    1673         Element search_element = (Element) search_elements.item(i);
    1674         text.append(search_element.getAttribute(StaticStrings.NAME_ATTRIBUTE));
    1675         text.append(StaticStrings.SPACE_CHARACTER);
    1676         }
    1677         return text.substring(0, text.length() - 1);
    1678     }
    1679     else {
    1680         return null;
    1681     }
    1682     }
    1683 
    1684     static private String subcollectionToString(Element command_element, boolean show_extracted_namespace) {
    1685     StringBuffer text = new StringBuffer(StaticStrings.SUBCOLLECTION_STR);
    1686     text.append(StaticStrings.SPACE_CHARACTER);
    1687     text.append(command_element.getAttribute(StaticStrings.NAME_ATTRIBUTE));
    1688     text.append(StaticStrings.SPACE_CHARACTER);
    1689     text.append(StaticStrings.TAB_CHARACTER);
    1690     text.append(StaticStrings.SPEECH_CHARACTER);
    1691     if(command_element.getAttribute(StaticStrings.TYPE_ATTRIBUTE).equals(StaticStrings.EXCLUDE_STR)) {
    1692         text.append(StaticStrings.EXCLAMATION_CHARACTER);
    1693     }
    1694     String content_str = command_element.getAttribute(StaticStrings.CONTENT_ATTRIBUTE);
    1695     if(!show_extracted_namespace && content_str.startsWith(StaticStrings.EXTRACTED_NAMESPACE)) {
    1696         content_str = content_str.substring(StaticStrings.EXTRACTED_NAMESPACE.length());
    1697     }
    1698     text.append(content_str);
    1699     content_str = null;
    1700     text.append(StaticStrings.SEPARATOR_CHARACTER);
    1701     text.append(XMLTools.getValue(command_element));
    1702     text.append(StaticStrings.SEPARATOR_CHARACTER);
    1703     String options_str = command_element.getAttribute(StaticStrings.OPTIONS_ATTRIBUTE);
    1704     if(options_str.length() > 0) {
    1705         text.append(options_str);
    1706     }
    1707     options_str = null;
    1708     text.append(StaticStrings.SPEECH_CHARACTER);
    1709     return text.toString();
    1710     }
    1711 
    1712     static private String subcollectionDefaultIndexToString(Element command_element) {
    1713     StringBuffer text = new StringBuffer(StaticStrings.SUBCOLLECTION_DEFAULT_INDEX_STR);
    1714     text.append(StaticStrings.TAB_CHARACTER);
    1715     NodeList content_elements = command_element.getElementsByTagName(StaticStrings.CONTENT_ELEMENT);
    1716     int content_elements_length = content_elements.getLength();
    1717     for(int j = 0; j < content_elements_length; j++) {
    1718         Element content_element = (Element) content_elements.item(j);
    1719         text.append(content_element.getAttribute(StaticStrings.NAME_ATTRIBUTE));
    1720         if(j < content_elements_length - 1) {
    1721         text.append(StaticStrings.COMMA_CHARACTER);
    1722         }
    1723     }
    1724     return text.toString();
    1725     }
    1726 
    1727     static private String subcollectionIndexesToString(Element command_element) {
    1728     StringBuffer text = new StringBuffer(StaticStrings.SUBCOLLECTION_INDEX_STR);
    1729     text.append(StaticStrings.TAB_CHARACTER);
    1730     // Retrieve all of the subcollection index partitions
    1731     NodeList subcollectionindex_elements = command_element.getElementsByTagName(StaticStrings.INDEX_ELEMENT);
    1732     int subcollectionindex_elements_length = subcollectionindex_elements.getLength();
    1733     if(subcollectionindex_elements_length == 0) {
    1734         return null;
    1735     }
    1736     for(int j = 0; j < subcollectionindex_elements_length; j++) {
    1737         Element subcollectionindex_element = (Element) subcollectionindex_elements.item(j);
    1738         NodeList content_elements = subcollectionindex_element.getElementsByTagName(StaticStrings.CONTENT_ELEMENT);
    1739         int content_elements_length = content_elements.getLength();
    1740         for(int k = 0; k < content_elements_length; k++) {
    1741         Element content_element = (Element) content_elements.item(k);
    1742         text.append(content_element.getAttribute(StaticStrings.NAME_ATTRIBUTE));
    1743         if(k < content_elements_length - 1) {
    1744             text.append(StaticStrings.COMMA_CHARACTER);
    1745         }
    1746         }
    1747         if(j < subcollectionindex_elements_length - 1) {
    1748         text.append(StaticStrings.SPACE_CHARACTER);
    1749         }
    1750     }
    1751     return text.toString();
    1752     }
    1753 
    1754     static private String supercollectionToString(Element command_element) {
    1755     NodeList content_elements = command_element.getElementsByTagName(StaticStrings.COLLECTION_ELEMENT);
    1756     int content_elements_length = content_elements.getLength();
    1757     if(content_elements_length > 1) {
    1758         StringBuffer text = new StringBuffer(StaticStrings.SUPERCOLLECTION_STR);
    1759         text.append(StaticStrings.TAB_CHARACTER);
    1760         for(int j = 0; j < content_elements_length; j++) {
    1761         Element content_element = (Element) content_elements.item(j);
    1762         text.append(content_element.getAttribute(StaticStrings.NAME_ATTRIBUTE));
    1763         if(j < content_elements_length - 1) {
    1764             text.append(StaticStrings.SPACE_CHARACTER);
    1765         }
    1766         }
    1767         return text.toString();
    1768     }
    1769     return null;
    1770     }
    1771 
    1772     static private String unknownToString(Element command_element) {
    1773     return XMLTools.getValue(command_element);
    1774     }
    1775 
     1378    private Element parseSearchType (String command_str) {
     1379        Element command_element = null;
     1380        try {
     1381            StringTokenizer tokenizer = new StringTokenizer (command_str);
     1382            // First token is command type (searchtype)
     1383            tokenizer.nextToken ();
     1384            if(tokenizer.hasMoreTokens ()) {
     1385                command_element = document.createElement (StaticStrings.FORMAT_ELEMENT);
     1386                command_element.setAttribute (StaticStrings.NAME_ATTRIBUTE, "SearchTypes");
     1387                String value = tokenizer.nextToken ();
     1388                while(tokenizer.hasMoreTokens ()) {
     1389                    value += ","+tokenizer.nextToken ();
     1390                }
     1391                value = Codec.transform (value, Codec.GREENSTONE_TO_DOM);
     1392                XMLTools.setValue (command_element, value);
     1393            }
     1394        }
     1395        catch(Exception exception) {
     1396        }
     1397        return command_element;
     1398    }
     1399   
     1400    private Element parseSubCollection (String command_str) {
     1401        Element command_element = null;
     1402        try {
     1403            CommandTokenizer tokenizer = new CommandTokenizer (command_str);
     1404            if(tokenizer.countTokens () >= 3) {
     1405                command_element = document.createElement (StaticStrings.SUBCOLLECTION_ELEMENT);
     1406                // First token is command type
     1407                tokenizer.nextToken ();
     1408                // Then subcollection identifier
     1409                command_element.setAttribute (StaticStrings.NAME_ATTRIBUTE, tokenizer.nextToken ());
     1410                // Then finally the pattern used to build the subcollection partition
     1411                String full_pattern_str = tokenizer.nextToken ();
     1412                // Set inclusion/exclusion flag and remove any exclamation mark
     1413                boolean exclusion = full_pattern_str.startsWith (StaticStrings.EXCLAMATION_CHARACTER);
     1414                if (exclusion) {
     1415                    full_pattern_str = full_pattern_str.substring (1, full_pattern_str.length ());
     1416                    command_element.setAttribute (StaticStrings.TYPE_ATTRIBUTE, StaticStrings.EXCLUDE_STR);
     1417                }
     1418                else {
     1419                    command_element.setAttribute (StaticStrings.TYPE_ATTRIBUTE, StaticStrings.INCLUDE_STR);
     1420                }
     1421                StringTokenizer pattern_tokenizer = new StringTokenizer (full_pattern_str, StaticStrings.SEPARATOR_CHARACTER);
     1422                if(pattern_tokenizer.countTokens () >= 2) {
     1423                    String content_str = pattern_tokenizer.nextToken ();
     1424                    // Since the contents of indexes have to be certain keywords, or metadata elements, if the content isn't a keyword and doesn't yet have a namespace, append the extracted metadata namespace.
     1425                    if(!content_str.equals (StaticStrings.FILENAME_STR) && content_str.indexOf (StaticStrings.NS_SEP) == -1) {
     1426                        content_str = StaticStrings.EXTRACTED_NAMESPACE + content_str;
     1427                    }
     1428                    command_element.setAttribute (StaticStrings.CONTENT_ATTRIBUTE, content_str);
     1429                    XMLTools.setValue (command_element, pattern_tokenizer.nextToken ());
     1430                    if(pattern_tokenizer.hasMoreTokens ()) {
     1431                        command_element.setAttribute (StaticStrings.OPTIONS_ATTRIBUTE, pattern_tokenizer.nextToken ());
     1432                    }
     1433                }
     1434                pattern_tokenizer = null;
     1435            }
     1436        }
     1437        catch(Exception exception) {
     1438            exception.printStackTrace ();
     1439        }
     1440        return command_element;
     1441    }
     1442   
     1443    private Element parseSubCollectionDefaultIndex (String command_str) {
     1444        Element command_element = null;
     1445        try {
     1446            StringTokenizer tokenizer = new StringTokenizer (command_str);
     1447            if(tokenizer.countTokens () == 2) {
     1448                command_element = document.createElement (StaticStrings.SUBCOLLECTION_DEFAULT_INDEX_ELEMENT);
     1449                tokenizer.nextToken ();
     1450                //command_element.setAttribute(CONTENT_ATTRIBUTE, tokenizer.nextToken());
     1451                String content_str = tokenizer.nextToken ();
     1452                StringTokenizer content_tokenizer = new StringTokenizer (content_str, StaticStrings.COMMA_CHARACTER);
     1453                while(content_tokenizer.hasMoreTokens ()) {
     1454                    Element content_element = document.createElement (StaticStrings.CONTENT_ELEMENT);
     1455                    content_element.setAttribute (StaticStrings.NAME_ATTRIBUTE, content_tokenizer.nextToken ());
     1456                    command_element.appendChild (content_element);
     1457                    content_element = null;
     1458                }
     1459                content_tokenizer = null;
     1460                content_str = null;
     1461            }
     1462            tokenizer = null;
     1463        }
     1464        catch(Exception exception) {
     1465        }
     1466        return command_element;
     1467    }
     1468   
     1469    private Element parseSubCollectionIndex (String command_str) {
     1470        Element command_element = null;
     1471        try {
     1472            StringTokenizer tokenizer = new StringTokenizer (command_str);
     1473            tokenizer.nextToken ();
     1474            if(tokenizer.hasMoreTokens ()) {
     1475                command_element = document.createElement (StaticStrings.SUBCOLLECTION_INDEXES_ELEMENT);
     1476            }
     1477            while(tokenizer.hasMoreTokens ()) {
     1478                Element subcollectionindex_element = document.createElement (StaticStrings.INDEX_ELEMENT);
     1479                //command_element.setAttribute(CONTENT_ATTRIBUTE, tokenizer.nextToken());
     1480                String content_str = tokenizer.nextToken ();
     1481                StringTokenizer content_tokenizer = new StringTokenizer (content_str, StaticStrings.COMMA_CHARACTER);
     1482                while(content_tokenizer.hasMoreTokens ()) {
     1483                    Element content_element = document.createElement (StaticStrings.CONTENT_ELEMENT);
     1484                    content_element.setAttribute (StaticStrings.NAME_ATTRIBUTE, content_tokenizer.nextToken ());
     1485                    subcollectionindex_element.appendChild (content_element);
     1486                    content_element = null;
     1487                }
     1488                content_tokenizer = null;
     1489                content_str = null;
     1490                command_element.appendChild (subcollectionindex_element);
     1491                subcollectionindex_element = null;
     1492            }
     1493            tokenizer = null;
     1494        }
     1495        catch (Exception exception) {
     1496        }
     1497        return command_element;
     1498    }
     1499   
     1500    private Element parseSuperCollection (String command_str) {
     1501        Element command_element = null;
     1502        try {
     1503            StringTokenizer tokenizer = new StringTokenizer (command_str);
     1504            if(tokenizer.countTokens () >= 3) {
     1505                command_element = document.createElement (StaticStrings.SUPERCOLLECTION_ELEMENT);
     1506                tokenizer.nextToken ();
     1507                while(tokenizer.hasMoreTokens ()) {
     1508                    Element collection_element = document.createElement (StaticStrings.COLLECTION_ELEMENT);
     1509                    collection_element.setAttribute (StaticStrings.NAME_ATTRIBUTE, tokenizer.nextToken ());
     1510                    command_element.appendChild (collection_element);
     1511                    collection_element = null;
     1512                }
     1513            }
     1514            tokenizer = null;
     1515        }
     1516        catch(Exception exception) {
     1517        }
     1518        return command_element;
     1519    }
     1520   
     1521    static private String pluginToString (Element command_element, boolean show_extracted_namespace) {
     1522        StringBuffer text = new StringBuffer ();
     1523        if(!command_element.getAttribute (StaticStrings.SEPARATOR_ATTRIBUTE).equals (StaticStrings.TRUE_STR)) {
     1524            text.append (StaticStrings.PLUGIN_STR);
     1525            text.append (StaticStrings.TAB_CHARACTER);
     1526            text.append (StaticStrings.TAB_CHARACTER);
     1527            text.append (command_element.getAttribute (StaticStrings.TYPE_ATTRIBUTE));
     1528            // Retrieve, and output, the arguments
     1529            NodeList option_elements = command_element.getElementsByTagName (StaticStrings.OPTION_ELEMENT);
     1530            int option_elements_length = option_elements.getLength ();
     1531            if(option_elements_length > 0) {
     1532                for(int j = 0; j < option_elements_length; j++) {
     1533                    Element option_element = (Element) option_elements.item (j);
     1534                    if(option_element.getAttribute (StaticStrings.ASSIGNED_ATTRIBUTE).equals (StaticStrings.TRUE_STR)) {
     1535                        text.append (StaticStrings.SPACE_CHARACTER);
     1536                        text.append (StaticStrings.MINUS_CHARACTER);
     1537                        text.append (option_element.getAttribute (StaticStrings.NAME_ATTRIBUTE));
     1538                        String value_str = XMLTools.getValue (option_element);
     1539                        if(!show_extracted_namespace && value_str.startsWith (StaticStrings.EXTRACTED_NAMESPACE)) {
     1540                            value_str = value_str.substring (StaticStrings.EXTRACTED_NAMESPACE.length ());
     1541                        }
     1542                        if(value_str.length () > 0) {
     1543                            text.append (StaticStrings.SPACE_CHARACTER);
     1544                            if(value_str.indexOf (StaticStrings.SPACE_CHARACTER) == -1) {
     1545                                text.append (value_str);
     1546                            }
     1547                            else {
     1548                                text.append (StaticStrings.SPEECH_CHARACTER);
     1549                                text.append (value_str);
     1550                                text.append (StaticStrings.SPEECH_CHARACTER);
     1551                            }
     1552                        }
     1553                        value_str = null;
     1554                    }
     1555                    option_element = null;
     1556                }
     1557            }
     1558            option_elements = null;
     1559        }
     1560        return text.toString ();
     1561    }
     1562   
     1563    static private String searchtypeToString (Element command_element) {
     1564        if(command_element.getAttribute (StaticStrings.ASSIGNED_ATTRIBUTE).equals (StaticStrings.TRUE_STR)) {
     1565            StringBuffer text = new StringBuffer (StaticStrings.SEARCHTYPE_STR);
     1566            text.append (StaticStrings.TAB_CHARACTER);
     1567            NodeList search_elements = command_element.getElementsByTagName (StaticStrings.CONTENT_ELEMENT);
     1568            int search_elements_length = search_elements.getLength ();
     1569            for(int i = 0; i < search_elements_length; i++) {
     1570                Element search_element = (Element) search_elements.item (i);
     1571                text.append (search_element.getAttribute (StaticStrings.NAME_ATTRIBUTE));
     1572                text.append (StaticStrings.SPACE_CHARACTER);
     1573            }
     1574            return text.substring (0, text.length () - 1);
     1575        }
     1576        else {
     1577            return null;
     1578        }
     1579    }
     1580   
     1581    static private String subcollectionToString (Element command_element, boolean show_extracted_namespace) {
     1582        StringBuffer text = new StringBuffer (StaticStrings.SUBCOLLECTION_STR);
     1583        text.append (StaticStrings.SPACE_CHARACTER);
     1584        text.append (command_element.getAttribute (StaticStrings.NAME_ATTRIBUTE));
     1585        text.append (StaticStrings.SPACE_CHARACTER);
     1586        text.append (StaticStrings.TAB_CHARACTER);
     1587        text.append (StaticStrings.SPEECH_CHARACTER);
     1588        if(command_element.getAttribute (StaticStrings.TYPE_ATTRIBUTE).equals (StaticStrings.EXCLUDE_STR)) {
     1589            text.append (StaticStrings.EXCLAMATION_CHARACTER);
     1590        }
     1591        String content_str = command_element.getAttribute (StaticStrings.CONTENT_ATTRIBUTE);
     1592        if(!show_extracted_namespace && content_str.startsWith (StaticStrings.EXTRACTED_NAMESPACE)) {
     1593            content_str = content_str.substring (StaticStrings.EXTRACTED_NAMESPACE.length ());
     1594        }
     1595        text.append (content_str);
     1596        content_str = null;
     1597        text.append (StaticStrings.SEPARATOR_CHARACTER);
     1598        text.append (XMLTools.getValue (command_element));
     1599        text.append (StaticStrings.SEPARATOR_CHARACTER);
     1600        String options_str = command_element.getAttribute (StaticStrings.OPTIONS_ATTRIBUTE);
     1601        if(options_str.length () > 0) {
     1602            text.append (options_str);
     1603        }
     1604        options_str = null;
     1605        text.append (StaticStrings.SPEECH_CHARACTER);
     1606        return text.toString ();
     1607    }
     1608   
     1609    static private String subcollectionDefaultIndexToString (Element command_element) {
     1610        StringBuffer text = new StringBuffer (StaticStrings.SUBCOLLECTION_DEFAULT_INDEX_STR);
     1611        text.append (StaticStrings.TAB_CHARACTER);
     1612        NodeList content_elements = command_element.getElementsByTagName (StaticStrings.CONTENT_ELEMENT);
     1613        int content_elements_length = content_elements.getLength ();
     1614        for(int j = 0; j < content_elements_length; j++) {
     1615            Element content_element = (Element) content_elements.item (j);
     1616            text.append (content_element.getAttribute (StaticStrings.NAME_ATTRIBUTE));
     1617            if(j < content_elements_length - 1) {
     1618                text.append (StaticStrings.COMMA_CHARACTER);
     1619            }
     1620        }
     1621        return text.toString ();
     1622    }
     1623   
     1624    static private String subcollectionIndexesToString (Element command_element) {
     1625        StringBuffer text = new StringBuffer (StaticStrings.SUBCOLLECTION_INDEX_STR);
     1626        text.append (StaticStrings.TAB_CHARACTER);
     1627        // Retrieve all of the subcollection index partitions
     1628        NodeList subcollectionindex_elements = command_element.getElementsByTagName (StaticStrings.INDEX_ELEMENT);
     1629        int subcollectionindex_elements_length = subcollectionindex_elements.getLength ();
     1630        if(subcollectionindex_elements_length == 0) {
     1631            return null;
     1632        }
     1633        for(int j = 0; j < subcollectionindex_elements_length; j++) {
     1634            Element subcollectionindex_element = (Element) subcollectionindex_elements.item (j);
     1635            NodeList content_elements = subcollectionindex_element.getElementsByTagName (StaticStrings.CONTENT_ELEMENT);
     1636            int content_elements_length = content_elements.getLength ();
     1637            for(int k = 0; k < content_elements_length; k++) {
     1638                Element content_element = (Element) content_elements.item (k);
     1639                text.append (content_element.getAttribute (StaticStrings.NAME_ATTRIBUTE));
     1640                if(k < content_elements_length - 1) {
     1641                    text.append (StaticStrings.COMMA_CHARACTER);
     1642                }
     1643            }
     1644            if(j < subcollectionindex_elements_length - 1) {
     1645                text.append (StaticStrings.SPACE_CHARACTER);
     1646            }
     1647        }
     1648        return text.toString ();
     1649    }
     1650   
     1651    static private String supercollectionToString (Element command_element) {
     1652        NodeList content_elements = command_element.getElementsByTagName (StaticStrings.COLLECTION_ELEMENT);
     1653        int content_elements_length = content_elements.getLength ();
     1654        if(content_elements_length > 1) {
     1655            StringBuffer text = new StringBuffer (StaticStrings.SUPERCOLLECTION_STR);
     1656            text.append (StaticStrings.TAB_CHARACTER);
     1657            for(int j = 0; j < content_elements_length; j++) {
     1658                Element content_element = (Element) content_elements.item (j);
     1659                text.append (content_element.getAttribute (StaticStrings.NAME_ATTRIBUTE));
     1660                if(j < content_elements_length - 1) {
     1661                    text.append (StaticStrings.SPACE_CHARACTER);
     1662                }
     1663            }
     1664            return text.toString ();
     1665        }
     1666        return null;
     1667    }
     1668   
     1669    static private String unknownToString (Element command_element) {
     1670        return XMLTools.getValue (command_element);
     1671    }
     1672   
    17761673    /** Write the text to the buffer. This is used so we don't have to worry about storing intermediate String values just so we can calaulate length and offset.
    17771674     * @param writer the BufferedWriter to which the str will be written
    17781675     * @param str the String to be written
    17791676     */
    1780     private void write(BufferedWriter writer, String str)
    1781     throws IOException {
    1782     writer.write(str, 0, str.length());
    1783     }
     1677    private void write (BufferedWriter writer, String str)
     1678    throws IOException {
     1679        writer.write (str, 0, str.length ());
     1680    }
     1681   
     1682    /** ********************************************************************************************************
     1683        The code from this point below are used for greenstone 3 collection configuration, i.e., read ColletionConfig.xml
     1684     * into the internal DOM tree, and convert the internal DOM tree back to CollectionConfig.xml.
     1685     *
     1686    Methods named 'doXXXX' are for convert collectionConfig.xml into the internal configuration xml structure;
     1687    Methods named 'convertXXXX' are for convert the internal configuration xml structure back to collectionConfig.xml.
     1688    ************************************************************************************************************ */
     1689   
     1690    /**Arguments:  metadataListNode->the 'displayItemList' element in collectionConfig.xml
     1691                name_value->the value of the 'name' attribute of 'index' element;
     1692                att_value->the value of the 'name' attribute of 'displayItem' element
     1693    return:     an ArrayList of the contructed 'CollectionMetadata' elements
     1694    */
     1695    private ArrayList doDisplayItemList (Document to, Node displayListNode, String att_value, String name_value) {
     1696        Element toElement = to.getDocumentElement ();
     1697        ArrayList display_item_list = new ArrayList ();
     1698        ArrayList item_list = XMLTools.getNamedElementList ((Element)displayListNode,
     1699        StaticStrings.DISPLAYITEM_STR, StaticStrings.NAME_ATTRIBUTE, att_value);
     1700        if (item_list == null) {
     1701            return null;
     1702        }
     1703       
     1704        for (int i=0; i<item_list.size (); i++) {
     1705            Element item = (Element)item_list.get (i);
     1706            String text = XMLTools.getNodeText (item);
     1707           
     1708            //If there is nothing to display, don't bother creating the element
     1709            if (text == "") {
     1710                continue;
     1711            }
     1712            //get the value in 'lang=value'
     1713            String lang = item.getAttribute (StaticStrings.LANG_STR);
     1714           
     1715            Element e = to.createElement (StaticStrings.COLLECTIONMETADATA_ELEMENT);
     1716            e.setAttribute (StaticStrings.ASSIGNED_ATTRIBUTE, StaticStrings.TRUE_STR);
     1717            e.setAttribute (StaticStrings.NAME_ATTRIBUTE, name_value);
     1718            e.setAttribute (StaticStrings.LANGUAGE_ATTRIBUTE, lang);
     1719            XMLTools.setNodeText (e, text);
     1720           
     1721            display_item_list.add (e);
     1722        }
     1723        return display_item_list;
     1724    }
     1725   
     1726    private ArrayList doMetadataList (Document to, Node metadataListNode, String ele_name, String att_value) {
     1727        Element toElement = to.getDocumentElement ();
     1728        ArrayList metadata_list = new ArrayList ();
     1729       
     1730        ArrayList item_list = XMLTools.getNamedElementList ((Element)metadataListNode,
     1731        StaticStrings.METADATA_STR, StaticStrings.NAME_ATTRIBUTE, att_value);
     1732        if (item_list == null) {
     1733            return null;
     1734        }
     1735       
     1736        for (int i=0; i<item_list.size (); i++) {
     1737            Element item = (Element)item_list.get (i);
     1738            String text = XMLTools.getNodeText (item);
     1739           
     1740            //If there is nothing to display, don't bother creating the element
     1741            if (text == "") {
     1742                continue;
     1743            }
     1744            //get the value in 'lang=value'
     1745            String lang = item.getAttribute (StaticStrings.LANG_STR);
     1746           
     1747            Element element = to.createElement (ele_name);
     1748            element.setAttribute (StaticStrings.NAME_ATTRIBUTE, att_value);
     1749            element.setAttribute (StaticStrings.LANGUAGE_ATTRIBUTE, lang);
     1750            element.setAttribute (StaticStrings.ASSIGNED_ATTRIBUTE, StaticStrings.TRUE_STR);
     1751            element.setAttribute (StaticStrings.SPECIAL_ATTRIBUTE, StaticStrings.TRUE_STR);
     1752            XMLTools.setNodeText (element, text);
     1753           
     1754            metadata_list.add (element);
     1755        }
     1756        return metadata_list;
     1757    }
     1758    // 'to' is the internal structure
     1759    private void doMGIndexes (Document to, Node searchNode) {
     1760        Element toElement = to.getDocumentElement ();
     1761        Element indexes_element = to.createElement (StaticStrings.INDEXES_ELEMENT);//<Indexes>
     1762        indexes_element.setAttribute (StaticStrings.ASSIGNED_ATTRIBUTE, StaticStrings.TRUE_STR);
     1763        indexes_element.setAttribute (StaticStrings.MGPP_ATTRIBUTE, StaticStrings.FALSE_STR);
     1764       
     1765        NodeList index_children = ((Element)searchNode).getElementsByTagName (StaticStrings.INDEX_LOW_STR);//index
     1766        int num_nodes = index_children.getLength ();
     1767       
     1768        for (int i=0; i<num_nodes; i++) {
     1769            Element e = (Element)index_children.item (i);
     1770            String index_str = e.getAttribute (StaticStrings.NAME_ATTRIBUTE);
     1771            String index_str_display = index_str;//used for creating collectionmetadata for this index
     1772            Element index_element = to.createElement (StaticStrings.INDEX_ELEMENT);//<Index>
     1773           
     1774            // For mg, it's the 'Old G2.38 and earlier' that use level:source tuplets, but we double check it anyway
     1775            boolean old_index = true;
     1776            if(index_str.indexOf (StaticStrings.COLON_CHARACTER) == -1) {
     1777                // It doesn't contain ':' character
     1778                System.err.println ("Something is wrong! the index should be level:source tuplets.");
     1779                old_index = false;
     1780            }
     1781            else {
     1782                // Handling 'index' element
     1783                index_element.setAttribute (StaticStrings.LEVEL_ATTRIBUTE,
     1784                index_str.substring (0, index_str.indexOf (StaticStrings.COLON_CHARACTER)));
     1785                index_str = index_str.substring (index_str.indexOf (StaticStrings.COLON_CHARACTER) + 1);
     1786               
     1787                //Each index may have a list of comma-separated strings.
     1788                //split them into 'content' elements in the internal structure
     1789                StringTokenizer content_tokenizer = new StringTokenizer (index_str, StaticStrings.COMMA_CHARACTER);
     1790                //index_str = "";
     1791                while(content_tokenizer.hasMoreTokens ()) {
     1792                    // Replace index_str to be qualified name, eg. dc.Subject and keywords insread of dc.Subject.
     1793                   
     1794                   
     1795                    Element content_element = to.createElement (StaticStrings.CONTENT_ELEMENT);
     1796                    String content_str = content_tokenizer.nextToken ();
     1797                    // Since the contents of indexes have to be certain keywords, or metadata elements,
     1798                    //if the content isn't a keyword and doesn't yet have a namespace, append the extracted metadata namespace.
     1799                    if(content_str.indexOf (StaticStrings.NS_SEP) == -1) {
     1800                        if(content_str.equals (StaticStrings.TEXT_STR) ||
     1801                        (!old_index && content_str.equals (StaticStrings.ALLFIELDS_STR))) {
     1802                            // in this case, do nothing
     1803                        }
     1804                        else {
     1805                            content_str = StaticStrings.EXTRACTED_NAMESPACE + content_str;
     1806                        }
     1807                    }
     1808                   
     1809                    content_element.setAttribute (StaticStrings.NAME_ATTRIBUTE, content_str);
     1810                    index_element.appendChild (content_element);
     1811                    content_element = null;
     1812                }   // while ends
     1813               
     1814                indexes_element.appendChild (index_element);
     1815               
     1816                // Handling 'displayItem' elements and Constructing 'collectionmetadata' elements
     1817                // Use the fully qualified index names
     1818                ArrayList collectionmetadata_list = doDisplayItemList (to, e, StaticStrings.NAME_ATTRIBUTE, index_str_display);
     1819                appendArrayList (toElement, collectionmetadata_list);
     1820            } //else ends
     1821        } //for loop ends
     1822        appendProperly (toElement, indexes_element);
     1823       
     1824        //***//
     1825        // create another set of <indexes> which will be used when user switches to MGPP/LUCENE
     1826        // i.e. we build a default index set for a start
     1827       
     1828        String []index_strs =
     1829        {StaticStrings.TEXT_STR,
     1830         StaticStrings.EXTRACTED_NAMESPACE + StaticStrings.TITLE_ELEMENT,
     1831         StaticStrings.EXTRACTED_NAMESPACE + StaticStrings.SOURCE_ELEMENT};
     1832         
     1833         Element mgpp_indexes = to.createElement (StaticStrings.INDEXES_ELEMENT);//<Indexes>
     1834         mgpp_indexes.setAttribute (StaticStrings.ASSIGNED_ATTRIBUTE, StaticStrings.FALSE_STR);
     1835         mgpp_indexes.setAttribute (StaticStrings.MGPP_ATTRIBUTE, StaticStrings.TRUE_STR);
     1836         for (int i=0; i<index_strs.length; i++) {
     1837             Element index_element = to.createElement (StaticStrings.INDEX_ELEMENT);//<Index>
     1838             Element content_element = to.createElement (StaticStrings.CONTENT_ELEMENT);
     1839             content_element.setAttribute (StaticStrings.NAME_ATTRIBUTE, index_strs[i]);
     1840             index_element.appendChild (content_element);
     1841             mgpp_indexes.appendChild (index_element);
     1842             
     1843             // Contructing 'collectionmetadata' elements for 'mgpp' indexes
     1844             Element collectionmetadata = to.createElement (StaticStrings.COLLECTIONMETADATA_ELEMENT);
     1845             collectionmetadata.setAttribute (StaticStrings.ASSIGNED_ATTRIBUTE, StaticStrings.TRUE_STR);
     1846             collectionmetadata.setAttribute (StaticStrings.NAME_ATTRIBUTE, index_strs[i]);
     1847             collectionmetadata.setAttribute (StaticStrings.LANGUAGE_ATTRIBUTE, StaticStrings.ENGLISH_LANGUAGE_STR);
     1848             if (index_strs[i].indexOf (StaticStrings.NS_SEP) != -1) {
     1849                 index_strs[i] = index_strs[i].substring (index_strs[i].indexOf (StaticStrings.NS_SEP) + 1);
     1850             }
     1851             XMLTools.setNodeText (collectionmetadata, index_strs[i]);
     1852             
     1853             appendProperly (toElement, collectionmetadata);
     1854             
     1855         }
     1856         appendProperly (toElement, mgpp_indexes);
     1857    }
     1858   
     1859    //This is actually doing indexes for both mgpp and lucene
     1860    private void doMGPPIndexes (Document to, Node searchNode) {
     1861        Element toElement = to.getDocumentElement ();
     1862        Element indexes_element = to.createElement (StaticStrings.INDEXES_ELEMENT);//<Indexes>
     1863        indexes_element.setAttribute (StaticStrings.ASSIGNED_ATTRIBUTE, StaticStrings.TRUE_STR);
     1864        indexes_element.setAttribute (StaticStrings.MGPP_ATTRIBUTE, StaticStrings.TRUE_STR);
     1865       
     1866        NodeList index_children = ((Element)searchNode).getElementsByTagName (StaticStrings.INDEX_LOW_STR);//index
     1867        int num_nodes = index_children.getLength ();
     1868       
     1869        for (int i=0; i<num_nodes; i++) {
     1870           
     1871            Element index_element = to.createElement (StaticStrings.INDEX_ELEMENT);//<Index>
     1872            Element e = (Element)index_children.item (i);
     1873            String index_str = e.getAttribute (StaticStrings.NAME_ATTRIBUTE);
     1874            String index_str_display = index_str;//for creating collectionmetadata for this index
     1875           
     1876            // Handling 'index' element
     1877            // Double check to make sure it's not colon separated style index.
     1878            boolean old_index = false;
     1879            if(index_str.indexOf (StaticStrings.COLON_CHARACTER) != -1) {
     1880                System.err.println ("Something is wrong! the index should NOT be level:source tuplets style.");
     1881                old_index = true;
     1882            }
     1883            //Each index may have a list of comma-separated strings.
     1884            //split them into 'content' elements in the internal structure
     1885            StringTokenizer content_tokenizer = new StringTokenizer (index_str, StaticStrings.COMMA_CHARACTER);
     1886            //index_str = "";
     1887            while(content_tokenizer.hasMoreTokens ()) {
     1888                // Replace index_str to be qualified name, eg. dc.Subject and keywords insread of dc.Subject.             
     1889               
     1890                Element content_element = to.createElement (StaticStrings.CONTENT_ELEMENT);
     1891                String content_str = content_tokenizer.nextToken ();
     1892                // Since the contents of indexes have to be certain keywords, or metadata elements, if the content isn't a keyword and doesn't yet have a namespace, append the extracted metadata namespace.
     1893                if(content_str.indexOf (StaticStrings.NS_SEP) == -1) {
     1894                    if(content_str.equals (StaticStrings.TEXT_STR)) {
     1895                        // in this case, do nothing
     1896                    }
     1897                    else {
     1898                        content_str = StaticStrings.EXTRACTED_NAMESPACE + content_str;
     1899                    }
     1900                }
     1901                content_element.setAttribute (StaticStrings.NAME_ATTRIBUTE, content_str);
     1902                index_element.appendChild (content_element);
     1903                content_element = null;
     1904            } //while ends
     1905           
     1906            indexes_element.appendChild (index_element);
     1907           
     1908           
     1909            index_element = null;
     1910           
     1911            // Handling 'displayItem' element of this 'index' element
     1912            // 'e' is the parent element 'index' of 'displayItem' element
     1913            ArrayList collectionmetadata_list = doDisplayItemList (to, e, StaticStrings.NAME_ATTRIBUTE, index_str_display);
     1914            appendArrayList (toElement, collectionmetadata_list);
     1915           
     1916           
     1917        } // for loop ends
     1918        toElement.appendChild (indexes_element);
     1919       
     1920        // create another set of <indexes> which will be used when user switches to MG
     1921        // i.e. we build a default index set for a start
     1922        Element mg_indexes = to.createElement (StaticStrings.INDEXES_ELEMENT);//<Indexes>
     1923        mg_indexes.setAttribute (StaticStrings.ASSIGNED_ATTRIBUTE, StaticStrings.FALSE_STR);
     1924        mg_indexes.setAttribute (StaticStrings.MGPP_ATTRIBUTE, StaticStrings.FALSE_STR);
     1925       
     1926        //put the namespace '.ex' as prefix to the indexes
     1927        String []index_strs =
     1928        {StaticStrings.TEXT_STR,
     1929         StaticStrings.EXTRACTED_NAMESPACE + StaticStrings.TITLE_ELEMENT,
     1930         StaticStrings.EXTRACTED_NAMESPACE + StaticStrings.SOURCE_ELEMENT};
     1931         for (int i=0; i<index_strs.length; i++) {
     1932             Element index_element = to.createElement (StaticStrings.INDEX_ELEMENT);//<Index>
     1933             index_element.setAttribute (StaticStrings.LEVEL_ATTRIBUTE, StaticStrings.DOCUMENT_STR);
     1934             Element content_element = to.createElement (StaticStrings.CONTENT_ELEMENT);
     1935             content_element.setAttribute (StaticStrings.NAME_ATTRIBUTE, index_strs[i]);
     1936             index_element.appendChild (content_element);
     1937             
     1938             mg_indexes.appendChild (index_element);
     1939             
     1940             // Contructing 'collectionmetadata' elements for 'mg' indexes
     1941             Element collectionmetadata = to.createElement (StaticStrings.COLLECTIONMETADATA_ELEMENT);
     1942             collectionmetadata.setAttribute (StaticStrings.ASSIGNED_ATTRIBUTE, StaticStrings.TRUE_STR);
     1943             String temp = StaticStrings.DOCUMENT_STR.concat (StaticStrings.COLON_CHARACTER).concat (index_strs[i]);
     1944             collectionmetadata.setAttribute (StaticStrings.NAME_ATTRIBUTE, temp);
     1945             collectionmetadata.setAttribute (StaticStrings.LANGUAGE_ATTRIBUTE, StaticStrings.ENGLISH_LANGUAGE_STR);
     1946             if (index_strs[i].indexOf (StaticStrings.NS_SEP) != -1) {
     1947                 index_strs[i] = index_strs[i].substring (index_strs[i].indexOf (StaticStrings.NS_SEP) + 1);
     1948             }
     1949             XMLTools.setNodeText (collectionmetadata, index_strs[i]);
     1950             
     1951             appendProperly (toElement, collectionmetadata);
     1952             
     1953         }
     1954         toElement.appendChild (mg_indexes);
     1955         
     1956    }
     1957   
     1958    private void doDisplayFormat (Document to, Element from) {
     1959        //display element in the xml file
     1960        Element de = (Element)XMLTools.getChildByTagName (from, StaticStrings.DISPLAY_STR);
     1961        if (de == null) {
     1962            return;
     1963        }
     1964        //format element in the display element
     1965        Element fe = (Element)XMLTools.getChildByTagName (de, StaticStrings.FORMAT_STR);
     1966
     1967        to.getDocumentElement ().appendChild (doFormat(to, fe, StaticStrings.DISPLAY_STR));
     1968    }
     1969
     1970    //construct 'DefaultIndex' element in the internal structure from collectionConfig.xml
     1971    private void doDefaultIndex (Document to, Node searchNode) {
     1972        Element toElement = to.getDocumentElement ();
     1973        Element default_index_element = to.createElement (StaticStrings.INDEX_DEFAULT_ELEMENT);
     1974        default_index_element.setAttribute (StaticStrings.ASSIGNED_ATTRIBUTE, StaticStrings.TRUE_STR);
     1975       
     1976        Element e = (Element)XMLTools.getChildByTagName (searchNode, StaticStrings.INDEX_DEFAULT_ELEMENT_LOWERCASE);//defaultIndex
     1977        if (e == null) {
     1978            return;
     1979        }
     1980        String index_str = e.getAttribute (StaticStrings.NAME_ATTRIBUTE);
     1981       
     1982        boolean old_index = false;
     1983        if(index_str.indexOf (StaticStrings.COLON_CHARACTER) != -1) {
     1984            //The index is 'level:source tuplets' which is for mg. Take out 'level'
     1985            old_index = true;
     1986            default_index_element.setAttribute (StaticStrings.LEVEL_ATTRIBUTE,
     1987            index_str.substring (0, index_str.indexOf (StaticStrings.COLON_CHARACTER)));
     1988            index_str = index_str.substring (index_str.indexOf (StaticStrings.COLON_CHARACTER) + 1);
     1989        } else {
     1990            default_index_element.setAttribute (StaticStrings.LEVEL_ATTRIBUTE, "");
     1991        }
     1992       
     1993        //Each index may have a list of comma-separated strings.
     1994        //split them into 'content' elements in the internal structure
     1995        StringTokenizer content_tokenizer = new StringTokenizer (index_str, StaticStrings.COMMA_CHARACTER);
     1996        while(content_tokenizer.hasMoreTokens ()) {
     1997            Element content_element = to.createElement (StaticStrings.CONTENT_ELEMENT);
     1998            String content_str = content_tokenizer.nextToken ();
     1999            // Since the contents of indexes have to be certain keywords, or metadata elements, if the content isn't a keyword and doesn't yet have a namespace, append the extracted metadata namespace.
     2000            if(content_str.indexOf (StaticStrings.NS_SEP) == -1) {
     2001                if(content_str.equals (StaticStrings.TEXT_STR) ||
     2002                (!old_index && content_str.equals (StaticStrings.ALLFIELDS_STR))) {
     2003                    // in this case, do nothing
     2004                }
     2005                else {
     2006                    content_str = StaticStrings.EXTRACTED_NAMESPACE + content_str;
     2007                }
     2008            }
     2009
     2010            content_element.setAttribute (StaticStrings.NAME_ATTRIBUTE, content_str);
     2011            default_index_element.appendChild (content_element);
     2012            content_element = null;
     2013        }
     2014        appendProperly (toElement, default_index_element);
     2015    }
     2016    // For mg, this method is still called, but make it 'assigned=false'
     2017    private void doDefaultLevel (Document to, Node searchNode) {
     2018        Element toElement = to.getDocumentElement ();
     2019        Element default_index_option = to.createElement (StaticStrings.INDEXOPTION_DEFAULT_ELEMENT);
     2020        default_index_option.setAttribute (StaticStrings.NAME_STR, StaticStrings.LEVEL_DEFAULT_STR);
     2021       
     2022        Element e = (Element)XMLTools.getChildByTagName (searchNode, StaticStrings.LEVEL_DEFAULT_ELEMENT);
     2023        if (e != null) {
     2024            default_index_option.setAttribute (StaticStrings.ASSIGNED_ATTRIBUTE, StaticStrings.TRUE_STR);
     2025            String level = e.getAttribute (StaticStrings.NAME_ATTRIBUTE);
     2026            default_index_option.setAttribute (StaticStrings.VALUE_ATTRIBUTE, level);
     2027        } else {
     2028            //In the case of mg, there's no level! build a default one using 'assigned=false value=document'
     2029            default_index_option.setAttribute (StaticStrings.ASSIGNED_ATTRIBUTE, StaticStrings.FALSE_STR);
     2030            default_index_option.setAttribute (StaticStrings.VALUE_ATTRIBUTE, StaticStrings.DOCUMENT_STR);
     2031        }
     2032        appendProperly (toElement, default_index_option);
     2033    }
     2034   
     2035    // Transform plugins (pluginListNode) of collectionConfig.xml into the internal structure (i.e. Document to)
     2036    private void doPlugin (Document to, Node pluginListNode) {
     2037        Element toElement = to.getDocumentElement ();
     2038        NodeList plugin_children = ((Element)pluginListNode).getElementsByTagName (StaticStrings.PLUGIN_STR);
     2039        int plugin_nodes = plugin_children.getLength ();
     2040       
     2041        if (plugin_nodes < 1) {
     2042            return;
     2043        }
     2044       
     2045        for (int i=0; i<plugin_nodes; i++) {
     2046            Element e = (Element)plugin_children.item (i);
     2047            String str = e.getAttribute (StaticStrings.NAME_ATTRIBUTE);
     2048            Element plugin_element = to.createElement (StaticStrings.PLUGIN_ELEMENT);
     2049            plugin_element.setAttribute (StaticStrings.TYPE_ATTRIBUTE, str);
     2050           
     2051           
     2052            NodeList option_children = e.getElementsByTagName (StaticStrings.OPTION_STR);
     2053           
     2054            for (int j=0; j<option_children.getLength (); j++) {
     2055                Element el = (Element)option_children.item (j);
     2056                String name_str = el.getAttribute (StaticStrings.NAME_ATTRIBUTE);
     2057                if (name_str.startsWith (StaticStrings.MINUS_CHARACTER)) {
     2058                    name_str = name_str.substring (1);
     2059                }
     2060                String value_str = el.getAttribute (StaticStrings.VALUE_ATTRIBUTE);
     2061                Element option_element = null;
     2062               
     2063                if (name_str.equals ("") && !value_str.equals ("")) {
     2064                    continue;
     2065                }
     2066               
     2067               
     2068                option_element = to.createElement (StaticStrings.OPTION_ELEMENT);
     2069                option_element.setAttribute (StaticStrings.ASSIGNED_ATTRIBUTE, StaticStrings.TRUE_STR);
     2070                if(name_str.equals (StaticStrings.RECPLUG_STR) && value_str.equals (StaticStrings.USE_METADATA_FILES_ARGUMENT)) {
     2071                    continue; // ignore this option
     2072                }
     2073               
     2074                if(value_str != null) {
     2075                    // Remove any speech marks appended in strings containing whitespace
     2076                    if(value_str.startsWith (StaticStrings.SPEECH_CHARACTER) && value_str.endsWith (StaticStrings.SPEECH_CHARACTER)) {
     2077                        value_str = value_str.substring (1, value_str.length () - 1);
     2078                    }
     2079                    if(name_str.equals (StaticStrings.METADATA_STR)) {
     2080                        // The metadata argument must be the fully qualified name of a metadata element, so if it doesn't yet have a namespace, append the extracted metadata namespace.
     2081                        String[] values = value_str.split (StaticStrings.COMMA_CHARACTER);
     2082                        value_str = "";
     2083                        for (int k=0; k<=values.length-1; k++) {
     2084                            if (values[k].indexOf (StaticStrings.NS_SEP) == -1) {
     2085                                values[k] = StaticStrings.EXTRACTED_NAMESPACE + values[k];
     2086                            }
     2087
     2088                            if (k < values.length-1) {
     2089                                value_str = value_str + values[k] + StaticStrings.COMMA_CHARACTER;
     2090                               
     2091                            } else {
     2092                                value_str = value_str + values[k];
     2093                            }
     2094                        }
     2095                    }
     2096                }
     2097                if (!name_str.equals ("")) {
     2098                    option_element.setAttribute (StaticStrings.NAME_ATTRIBUTE, name_str);
     2099                }
     2100                if (!value_str.equals ("")) {
     2101                    XMLTools.setNodeText (option_element, value_str);
     2102                }
     2103                plugin_element.appendChild (option_element);
     2104               
     2105            }
     2106           
     2107            appendProperly (toElement, plugin_element);
     2108        }
     2109       
     2110    }
     2111   
     2112    //Handle classifiers
     2113    private void doClassifier (Document to, Node browseNode) {
     2114        Element toElement = to.getDocumentElement ();
     2115        NodeList classifier_children = ((Element)browseNode).getElementsByTagName (StaticStrings.CLASSIFIER_STR);
     2116        int num_nodes = classifier_children.getLength ();
     2117       
     2118        if (num_nodes < 1) {
     2119            return;
     2120        }
     2121       
     2122        for (int i=0; i<num_nodes; i++) {
     2123            Element e = (Element)classifier_children.item (i);
     2124            String str = e.getAttribute (StaticStrings.NAME_ATTRIBUTE);
     2125            Element classify_element = to.createElement (StaticStrings.CLASSIFY_ELEMENT);
     2126            classify_element.setAttribute (StaticStrings.TYPE_ATTRIBUTE, str);
     2127           
     2128            String options_str = "";
     2129            NodeList option_children = e.getElementsByTagName (StaticStrings.OPTION_STR);
     2130            for (int j=0; j<option_children.getLength (); j++) {
     2131                Element el = (Element)option_children.item (j);
     2132                String name_str = el.getAttribute (StaticStrings.NAME_ATTRIBUTE);
     2133                options_str = options_str + ((name_str.equals(""))? "" : (" " + name_str));
     2134                if (name_str.startsWith (StaticStrings.MINUS_CHARACTER)) {
     2135                    name_str = name_str.substring (1);
     2136                }
     2137                String value_str = el.getAttribute (StaticStrings.VALUE_ATTRIBUTE);
     2138                options_str = options_str + ((name_str.equals(""))? "" : (" " + value_str));
     2139                Element option_element = null;
     2140               
     2141                if (name_str.equals ("") && !value_str.equals ("")) {
     2142                    continue; //invalid condition
     2143                }
     2144               
     2145                option_element = to.createElement (StaticStrings.OPTION_ELEMENT);
     2146                option_element.setAttribute (StaticStrings.ASSIGNED_ATTRIBUTE, StaticStrings.TRUE_STR);
     2147               
     2148                if (!name_str.equals ("")) {
     2149                    option_element.setAttribute (StaticStrings.NAME_ATTRIBUTE, name_str);
     2150                }
     2151               
     2152                if (!value_str.equals ("") && name_str.equals (StaticStrings.METADATA_STR)) {
     2153                    // The metadata argument must be the fully qualified name of a metadata element, so if it doesn't yet have a namespace, append the extracted metadata namespace.
     2154                    String[] values = value_str.split (StaticStrings.COMMA_CHARACTER);
     2155                    value_str = "";
     2156                    for (int k=0; k<=values.length-1; k++) {
     2157                        if (values[k].indexOf (StaticStrings.NS_SEP) == -1) {
     2158                            values[k] = StaticStrings.EXTRACTED_NAMESPACE + values[k];
     2159                        }
     2160                        else {
     2161                            MetadataElement metadata_element = MetadataTools.getMetadataElementWithName (values[k]);
     2162                            if (metadata_element != null) {
     2163                                values[k] = metadata_element.getDisplayName ();
     2164                            }
     2165                        }
     2166                        if (k < values.length-1) {
     2167                            value_str = value_str + values[k] + StaticStrings.COMMA_CHARACTER;
     2168                        } else {
     2169                            value_str = value_str + values[k];
     2170                        }
     2171                    }
     2172                }
     2173               
     2174                if (value_str != null && !value_str.equals ("")) {
     2175                    XMLTools.setNodeText (option_element, value_str);
     2176                }
     2177                classify_element.appendChild (option_element);
     2178            }
     2179            //format element for this classifier
     2180            Element format = (Element)XMLTools.getChildByTagName (e, StaticStrings.FORMAT_STR);
     2181            if(format != null) {
     2182                classify_element.appendChild (doFormat(to, format, null));
     2183            }
     2184            appendProperly (toElement, classify_element);
     2185        }
     2186       
     2187        // default format statement for all classifiers
     2188        Element default_classifier_format = (Element)XMLTools.getChildByTagName (browseNode, StaticStrings.FORMAT_STR);
     2189
     2190        to.getDocumentElement ().appendChild (doFormat(to, default_classifier_format, StaticStrings.BROWSE_STR));
     2191    }
     2192    private Element doFormat(Document to, Element format, String name_str) {
     2193            Element format_element = to.createElement (StaticStrings.FORMAT_STR);
     2194            if (name_str != null) {
     2195                format_element.setAttribute (StaticStrings.NAME_ATTRIBUTE, name_str);
     2196            }
     2197            if (format != null) {
     2198                String gsf_text = XMLTools.xmlNodeToStringWithoutNewline(format);
     2199               
     2200                if (gsf_text.startsWith("<") && (gsf_text.indexOf("<") != gsf_text.lastIndexOf("<"))) {
     2201                    gsf_text = gsf_text.substring(gsf_text.indexOf("<gsf"),
     2202                                          gsf_text.indexOf(StaticStrings.FORMAT_END_TAG));
     2203                }
     2204               
     2205                XMLTools.setNodeText(format_element, gsf_text);
     2206            }
     2207            return format_element;
     2208    }
     2209    // Handling 'subcollection' elements in 'search' element of 'collectionConfig.xml'
     2210    private void doSubcollection (Document to, Node searchNode) {
     2211        Element toElement = to.getDocumentElement ();
     2212        NodeList sub_children = ((Element)searchNode).getElementsByTagName (StaticStrings.SUBCOLLECTION_STR);
     2213        int sub_nodes = sub_children.getLength ();
     2214       
     2215        // There is no subcollection
     2216        if (sub_nodes < 1) {
     2217            return;
     2218        }
     2219       
     2220        for (int i=0; i<sub_nodes; i++) {
     2221            Element sub_child = (Element)sub_children.item (i);
     2222            String name_str = sub_child.getAttribute (StaticStrings.NAME_ATTRIBUTE);
     2223            String filter_str = sub_child.getAttribute (StaticStrings.FILTER_ATTRIBUTE);
     2224           
     2225            // filter_str is in the form '<! (if set)><metadata>/<metadata value>/<flag (if any)>'
     2226           
     2227            int pos = filter_str.indexOf (StaticStrings.SEPARATOR_CHARACTER);
     2228            String meta_str = "";
     2229            String meta_value_str = "";
     2230            String clude_str = "";
     2231            String flag_str = "";
     2232            if (pos == -1) {
     2233               
     2234                meta_str = meta_value_str = filter_str;
     2235                clude_str = StaticStrings.INCLUDE_STR;
     2236            } else {
     2237                clude_str = StaticStrings.INCLUDE_STR;
     2238                if (filter_str.startsWith (StaticStrings.EXCLAMATION_CHARACTER)) {
     2239                    clude_str = StaticStrings.EXCLUDE_STR;
     2240                    // Peel off "!"
     2241                    filter_str = filter_str.substring (StaticStrings.EXCLAMATION_CHARACTER.length ());
     2242                }
     2243               
     2244                String[] strs = filter_str.split (StaticStrings.SEPARATOR_CHARACTER);
     2245                if (strs[0] != null && strs[0] != "") {
     2246                    meta_str = strs[0];
     2247                }
     2248                if(!meta_str.equals (StaticStrings.FILENAME_STR) && meta_str.indexOf (StaticStrings.NS_SEP) == -1) {
     2249                    meta_str = StaticStrings.EXTRACTED_NAMESPACE + meta_str;
     2250                }
     2251               
     2252                if (strs[1] != null && strs[1] != "") {
     2253                    meta_value_str = strs[1];
     2254                }
     2255                if (strs.length > 2) {
     2256                    //This means there has been set a flag
     2257                    if (strs[2] != null && strs[2] != "") {
     2258                        flag_str = strs[2];
     2259                    }
     2260                }
     2261            }
     2262            Element subcollection_element = to.createElement (StaticStrings.SUBCOLLECTION_ELEMENT);
     2263            subcollection_element.setAttribute (StaticStrings.NAME_STR, name_str);
     2264            subcollection_element.setAttribute (StaticStrings.CONTENT_ATTRIBUTE, meta_str);
     2265            subcollection_element.setAttribute (StaticStrings.TYPE_ATTRIBUTE, clude_str);
     2266            if (flag_str != "") {
     2267                subcollection_element.setAttribute (StaticStrings.OPTIONS_ATTRIBUTE, flag_str);
     2268            }
     2269            XMLTools.setNodeText (subcollection_element, meta_value_str);
     2270           
     2271            toElement.appendChild (subcollection_element);
     2272        }
     2273    }
     2274    //Handle levels (document, section). In the internal structure, the element is called 'IndexOption'
     2275    private void doLevel (Document to, Node searchNode) {
     2276        Element toElement = to.getDocumentElement ();
     2277        NodeList level_children = ((Element)searchNode).getElementsByTagName (StaticStrings.LEVEL_ATTRIBUTE);
     2278        int level_nodes = level_children.getLength ();
     2279       
     2280        // it's mg, there's no level. So we construct a default 'indexOption' in the internal structure
     2281        if (level_nodes < 1) {
     2282            Element index_option = to.createElement (StaticStrings.INDEXOPTIONS_ELEMENT);
     2283            index_option.setAttribute (StaticStrings.ASSIGNED_ATTRIBUTE, StaticStrings.FALSE_STR);
     2284            index_option.setAttribute (StaticStrings.NAME_STR, StaticStrings.LEVELS_STR);
     2285           
     2286            Element option_element = to.createElement (StaticStrings.OPTION_ELEMENT);
     2287            option_element.setAttribute (StaticStrings.NAME_STR, StaticStrings.DOCUMENT_STR);
     2288            index_option.appendChild (option_element);
     2289           
     2290            appendProperly (toElement, index_option);
     2291           
     2292            return;
     2293        }
     2294       
     2295        Element index_option = to.createElement (StaticStrings.INDEXOPTIONS_ELEMENT);
     2296        index_option.setAttribute (StaticStrings.ASSIGNED_ATTRIBUTE, StaticStrings.TRUE_STR);
     2297        index_option.setAttribute (StaticStrings.NAME_STR, StaticStrings.LEVELS_STR);
     2298       
     2299        for (int i=0; i<level_nodes; i++) {
     2300            Element level_element = (Element)level_children.item (i);
     2301            String level_str = level_element.getAttribute (StaticStrings.NAME_ATTRIBUTE);
     2302            Element option_element = to.createElement (StaticStrings.OPTION_ELEMENT);
     2303            option_element.setAttribute (StaticStrings.NAME_STR, level_str);
     2304            index_option.appendChild (option_element);
     2305           
     2306           
     2307            // Contructing 'collectionmetadata' elements from the 'displayItem' of this 'level' element
     2308            ArrayList displayItem_list = XMLTools.getNamedElementList (level_element,
     2309            StaticStrings.DISPLAYITEM_STR, StaticStrings.NAME_ATTRIBUTE, StaticStrings.NAME_STR);
     2310            if (displayItem_list == null) {
     2311                return ;
     2312            }
     2313            for (int j=0; j<displayItem_list.size (); j++) {
     2314                Element item = (Element)displayItem_list.get (j);
     2315                String text = XMLTools.getNodeText (item);
     2316                String lang = item.getAttribute (StaticStrings.LANG_ATTRIBUTE);
     2317               
     2318                //If there is nothing to display, don't bother creating the element
     2319                if (text == "") {
     2320                    continue;
     2321                }
     2322                Element collectionmetadata = to.createElement (StaticStrings.COLLECTIONMETADATA_ELEMENT);
     2323                collectionmetadata.setAttribute (StaticStrings.ASSIGNED_ATTRIBUTE, StaticStrings.TRUE_STR);
     2324                collectionmetadata.setAttribute (StaticStrings.NAME_ATTRIBUTE, level_str);
     2325                collectionmetadata.setAttribute (StaticStrings.LANGUAGE_ATTRIBUTE, lang);
     2326                XMLTools.setNodeText (collectionmetadata, text);
     2327               
     2328                appendProperly (toElement, collectionmetadata);
     2329            }
     2330        }
     2331        appendProperly (toElement, index_option);
     2332    }
     2333    //Handle 'indexSubcollection' element of collectionConfig.xml,  which is called 'SubcollectionIndexes' in the internal structure. These contain the subcollection indexes (i.e. the filter or filter combinations), and displayed words for the filter names.
     2334    private void doIndexSubcollection (Document to, Node searchNode) {
     2335        Element toElement = to.getDocumentElement ();
     2336        NodeList index_sub_children = ((Element)searchNode).getElementsByTagName (StaticStrings.SUBCOLLECTION_INDEX_ELEMENT);
     2337        int num_nodes = index_sub_children.getLength ();
     2338       
     2339        // there is no subcollection index
     2340        if (num_nodes < 1) {
     2341            return;
     2342        }
     2343       
     2344        Element subcollection_indexes = to.createElement (StaticStrings.SUBCOLLECTION_INDEXES_ELEMENT);
     2345       
     2346        for (int i=0; i<num_nodes; i++) {
     2347            Element index_element = to.createElement (StaticStrings.INDEX_ELEMENT);
     2348            Element index_sub_child = (Element)index_sub_children.item (i);
     2349            String name_str = index_sub_child.getAttribute (StaticStrings.NAME_ATTRIBUTE);
     2350           
     2351            // name_str is in the form of comma separated strings, each of which is a subcollection filter name
     2352            String[] filters = name_str.split (StaticStrings.COMMA_CHARACTER);
     2353            for (int j=0; j<filters.length; j++) {
     2354               
     2355                Element content_element = to.createElement (StaticStrings.CONTENT_ELEMENT);
     2356                content_element.setAttribute (StaticStrings.NAME_STR, filters[j]);
     2357                index_element.appendChild (content_element);
     2358            }
     2359            subcollection_indexes.appendChild (index_element);
     2360           
     2361            // Contructing 'collectionmetadata' elements from the 'displayItem' of this 'indexSubcollection' element
     2362            ArrayList displayItem_list = XMLTools.getNamedElementList (index_sub_child,
     2363            StaticStrings.DISPLAYITEM_STR, StaticStrings.NAME_ATTRIBUTE, StaticStrings.NAME_STR);
     2364            if (displayItem_list == null) {
     2365                // there is no display item for this element
     2366                continue;
     2367            }
     2368            for (int j=0; j<displayItem_list.size (); j++) {
     2369                Element item = (Element)displayItem_list.get (j);
     2370                String text = XMLTools.getNodeText (item);
     2371                String lang = item.getAttribute (StaticStrings.LANG_ATTRIBUTE);
     2372               
     2373                //If there is nothing to display, don't bother creating the element
     2374                if (text == "") {
     2375                    continue;
     2376                }
     2377                Element collectionmetadata = to.createElement (StaticStrings.COLLECTIONMETADATA_ELEMENT);
     2378                collectionmetadata.setAttribute (StaticStrings.ASSIGNED_ATTRIBUTE, StaticStrings.TRUE_STR);
     2379                collectionmetadata.setAttribute (StaticStrings.NAME_ATTRIBUTE, name_str);
     2380                collectionmetadata.setAttribute (StaticStrings.LANGUAGE_ATTRIBUTE, lang);
     2381                XMLTools.setNodeText (collectionmetadata, text);
     2382               
     2383                appendProperly (toElement, collectionmetadata);
     2384            }
     2385        }
     2386        appendProperly (toElement, subcollection_indexes);
     2387    }
     2388    //Handle 'indexLanguage' element of collectionConfig.xml,  which is called 'Languages' in the internal structure. These contain the language indexes, and displayed words for those language index names.
     2389    private void doIndexLanguage (Document to, Node searchNode) {
     2390        Element toElement = to.getDocumentElement ();
     2391        NodeList index_sub_children = ((Element)searchNode).getElementsByTagName (StaticStrings.LANGUAGE_INDEX_ELEMENT);
     2392        int num_nodes = index_sub_children.getLength ();
     2393       
     2394        // there is no subcollection index
     2395        if (num_nodes < 1) {
     2396            return;
     2397        }
     2398       
     2399        Element language_indexes = to.createElement (StaticStrings.LANGUAGES_ELEMENT);
     2400       
     2401        for (int i=0; i<num_nodes; i++) {
     2402            Element language_element = to.createElement (StaticStrings.LANGUAGE_ELEMENT);
     2403            Element index_sub_child = (Element)index_sub_children.item (i);
     2404            String name_str = index_sub_child.getAttribute (StaticStrings.NAME_ATTRIBUTE);
     2405            language_element.setAttribute (StaticStrings.NAME_STR, name_str);
     2406            language_indexes.appendChild (language_element);
     2407           
     2408            // Contructing 'collectionmetadata' elements from the 'displayItem' of this 'indexLanguage' element
     2409            ArrayList displayItem_list = XMLTools.getNamedElementList (index_sub_child,
     2410            StaticStrings.DISPLAYITEM_STR, StaticStrings.NAME_ATTRIBUTE, StaticStrings.NAME_STR);
     2411            if (displayItem_list == null) {
     2412                // there is no display item for this element
     2413                continue;
     2414            }
     2415            for (int j=0; j<displayItem_list.size (); j++) {
     2416                Element item = (Element)displayItem_list.get (j);
     2417                String text = XMLTools.getNodeText (item);
     2418                String lang = item.getAttribute (StaticStrings.LANG_ATTRIBUTE);
     2419               
     2420                //If there is nothing to display, don't bother creating the element
     2421                if (text == "") {
     2422                    continue;
     2423                }
     2424                Element collectionmetadata = to.createElement (StaticStrings.COLLECTIONMETADATA_ELEMENT);
     2425                collectionmetadata.setAttribute (StaticStrings.ASSIGNED_ATTRIBUTE, StaticStrings.TRUE_STR);
     2426                collectionmetadata.setAttribute (StaticStrings.NAME_ATTRIBUTE, name_str);
     2427                collectionmetadata.setAttribute (StaticStrings.LANGUAGE_ATTRIBUTE, lang);
     2428                XMLTools.setNodeText (collectionmetadata, text);
     2429               
     2430                appendProperly (toElement, collectionmetadata);
     2431            }
     2432        }
     2433        toElement.appendChild (language_indexes);
     2434    }
     2435    // Handling both earchType and search format statement
     2436    private void doSearchFormat (Document to, Node searchNode) {
     2437        //There are two elements called <format> in <search>: one is for searchType; another is for format statement
     2438        NodeList format_children = ((Element)searchNode).getElementsByTagName (StaticStrings.FORMAT_STR);
     2439        int format_nodes = format_children.getLength ();
     2440        if (format_nodes < 1) {
     2441            return;
     2442        }
     2443        Element format = null;
     2444        Element search_type = null;
     2445        for(int i=0; i<format_nodes; i++) {
     2446            Node e = format_children.item (i);
     2447            if (e.hasAttributes () == false) {
     2448                //The format element for format statement has no any attribute
     2449                format = (Element)e;
     2450            }
     2451            else if (((Element)e).getAttribute (StaticStrings.NAME_ATTRIBUTE).equals(StaticStrings.SEARCHTYPE_ELEMENT)) {
     2452                search_type = (Element)e;
     2453            }
     2454        }
     2455        //format statement for search
     2456        if (format != null) {           
     2457            (to.getDocumentElement ()).appendChild (doFormat(to, format, StaticStrings.SEARCH_STR));
     2458        }
     2459        // searchType in search
     2460        if(search_type != null) {
     2461            String searchtype_str = XMLTools.getNodeText(search_type);
     2462       
     2463            Element search_type_element = to.createElement (StaticStrings.FORMAT_STR);
     2464            search_type_element.setAttribute (StaticStrings.NAME_ATTRIBUTE, StaticStrings.SEARCHTYPE_ELEMENT);
     2465            XMLTools.setNodeText(search_type_element, searchtype_str);
     2466       
     2467       
     2468            appendProperly (to.getDocumentElement (), search_type_element);
     2469        }
     2470    }
     2471    // Handling defaultIndexLanguage and languageMetadata in collectionConfig.xml ('elementNameFrom'); in the internal structure, they are called 'DefaultLanguage' and 'LanguageMetadata' ('elementNameTo') respectively.
     2472    // Converting from collectionConfig.xml to the internal xml structure.
     2473    private void doLanguageMetadata (Document to, Node searchNode) {
     2474        Element toElement = to.getDocumentElement ();
     2475        String elementNameFrom = StaticStrings.LANGUAGE_METADATA_ELEMENT_STR;
     2476        String elementNameTo = StaticStrings.LANGUAGE_METADATA_ELEMENT;
     2477        Node from_element = XMLTools.getChildByTagName (searchNode, elementNameFrom);
     2478        if (from_element == null) {
     2479            return; // such an element not found
     2480        }
     2481       
     2482        Element to_element = to.createElement (elementNameTo);
     2483       
     2484        String name_str = ((Element)from_element).getAttribute (StaticStrings.NAME_ATTRIBUTE);
     2485        if (name_str.indexOf (StaticStrings.NS_SEP) == -1) {
     2486            name_str = StaticStrings.EXTRACTED_NAMESPACE + name_str;
     2487        }
     2488        to_element.setAttribute (StaticStrings.NAME_ATTRIBUTE, name_str);
     2489        to_element.setAttribute (StaticStrings.ASSIGNED_ATTRIBUTE, StaticStrings.TRUE_STR);
     2490       
     2491        toElement.appendChild (to_element);
     2492    }
     2493    private void doReplaceListRef (Document to, Element from) {
     2494        Element toElement = to.getDocumentElement ();
     2495       
     2496        Node replace_element = XMLTools.getChildByTagName (from, StaticStrings.REPLACELISTREF_STR);
     2497        if (replace_element == null) {
     2498            return; // such an element not found
     2499        }
     2500       
     2501        Element to_element = XMLTools.duplicateElement (to, (Element)replace_element, true);
     2502        toElement.appendChild (to_element);
     2503    }
     2504    private void convertReplaceListRef (Document from, Document to) {
     2505        Element toElement = to.getDocumentElement ();
     2506       
     2507        Node replace_element = XMLTools.getChildByTagName (from.getDocumentElement (), StaticStrings.REPLACELISTREF_STR);
     2508        if (replace_element == null) {
     2509            return; // such an element not found
     2510        }
     2511       
     2512        Element to_element = XMLTools.duplicateElement (to, (Element)replace_element, true);
     2513        toElement.appendChild (to_element);
     2514    }
     2515    private void doDefaultIndexLanguage (Document to, Node searchNode) {
     2516        Element toElement = to.getDocumentElement ();
     2517        String elementNameFrom = StaticStrings.LANGUAGE_DEFAULT_INDEX_ELEMENT;
     2518        String elementNameTo = StaticStrings.LANGUAGE_DEFAULT_ELEMENT;
     2519        Node from_element = XMLTools.getChildByTagName (searchNode, elementNameFrom);
     2520        if (from_element == null) {
     2521            return; // such an element not found
     2522        }
     2523       
     2524        Element to_element = to.createElement (elementNameTo);
     2525       
     2526        String name_str = ((Element)from_element).getAttribute (StaticStrings.NAME_ATTRIBUTE);
     2527        to_element.setAttribute (StaticStrings.NAME_ATTRIBUTE, name_str);
     2528        to_element.setAttribute (StaticStrings.ASSIGNED_ATTRIBUTE, StaticStrings.TRUE_STR);
     2529       
     2530        toElement.appendChild (to_element);
     2531    }
     2532   
     2533    //Handle 'indexOption' (i.e. casefold, stem etc). In the internal structure, the element is called 'IndexOption'
     2534    private void doIndexOption (Document to, Node searchNode) {
     2535        Element toElement = to.getDocumentElement ();
     2536        Node index_option_node = XMLTools.getChildByTagName (searchNode, StaticStrings.INDEXOPTION_STR);
     2537        if (index_option_node == null) {
     2538            return;
     2539        }
     2540        NodeList option_children = ((Element)index_option_node).getElementsByTagName (StaticStrings.OPTION_STR);
     2541        int option_nodes = option_children.getLength ();
     2542       
     2543        // for lucene, there is no 'indexOption'. We build a default 'indexOption' and 'assigned=false' in case the user switches to mg or mgpp
     2544        if (option_nodes < 1) {
     2545            Element index_option = to.createElement (StaticStrings.INDEXOPTIONS_ELEMENT);
     2546            index_option.setAttribute (StaticStrings.ASSIGNED_ATTRIBUTE, StaticStrings.FALSE_STR);
     2547            index_option.setAttribute (StaticStrings.NAME_STR, StaticStrings.INDEXOPTIONS_STR);
     2548            String[] option_str =
     2549            { StaticStrings.CASEFOLD_OPTION_STR, StaticStrings.STEM_OPTION_STR };
     2550            for (int i=0; i<option_str.length; i++) {
     2551                Element option_element = to.createElement (StaticStrings.OPTION_ELEMENT);
     2552                option_element.setAttribute (StaticStrings.NAME_STR, option_str[i]);
     2553                index_option.appendChild (option_element);
     2554            }
     2555            appendProperly (toElement, index_option);
     2556            return;
     2557        }
     2558       
     2559        Element index_option = to.createElement (StaticStrings.INDEXOPTIONS_ELEMENT);
     2560        index_option.setAttribute (StaticStrings.ASSIGNED_ATTRIBUTE, StaticStrings.TRUE_STR);
     2561        index_option.setAttribute (StaticStrings.NAME_STR, StaticStrings.INDEXOPTIONS_STR);
     2562       
     2563        for (int i=0; i<option_nodes; i++) {
     2564            String option_str = ((Element)option_children.item (i)).getAttribute (StaticStrings.NAME_ATTRIBUTE);
     2565            Element option_element = to.createElement (StaticStrings.OPTION_ELEMENT);
     2566            option_element.setAttribute (StaticStrings.NAME_STR, option_str);
     2567            index_option.appendChild (option_element);
     2568        }
     2569        appendProperly (toElement, index_option);
     2570    }
     2571   
     2572    private Element doBuildType (Document to, String att_value) {
     2573       
     2574        //construct 'BuildType' element
     2575        Element element = to.createElement (StaticStrings.BUILDTYPE_ELEMENT);
     2576        element.setAttribute (StaticStrings.NAME_ATTRIBUTE, StaticStrings.BUILDTYPE_STR);
     2577        element.setAttribute (StaticStrings.LANGUAGE_ATTRIBUTE, StaticStrings.ENGLISH_LANGUAGE_STR);
     2578        element.setAttribute (StaticStrings.ASSIGNED_ATTRIBUTE, StaticStrings.TRUE_STR);
     2579        element.setAttribute (StaticStrings.SPECIAL_ATTRIBUTE, StaticStrings.TRUE_STR);
     2580
     2581        XMLTools.setNodeText (element, att_value);
     2582       
     2583        return element;
     2584    }
     2585   
     2586    // Convert 'description', 'smallicon' etc.
     2587    private void convertDisplayItemList (Document from, Document to) {
     2588        Element displayItemList = to.createElement (StaticStrings.DISPLAYITEMLIST_STR);
     2589        Element destination = to.getDocumentElement ();
     2590       
     2591        String []att_values =
     2592        {StaticStrings.COLLECTIONMETADATA_COLLECTIONEXTRA_STR,
     2593         StaticStrings.COLLECTIONMETADATA_ICONCOLLECTIONSMALL_STR,
     2594         StaticStrings.COLLECTIONMETADATA_ICONCOLLECTION_STR,
     2595         StaticStrings.COLLECTIONMETADATA_COLLECTIONNAME_STR};
     2596         
     2597         String []map_attrs =
     2598         {StaticStrings.DESCRIPTION_STR,
     2599          StaticStrings.SMALLICON_STR,
     2600          StaticStrings.ICON_STR,
     2601          StaticStrings.NAME_STR};
     2602         
     2603          for (int i=0; i<att_values.length; i++) {
     2604             
     2605              //dOc
     2606              ArrayList e_list = XMLTools.getNamedElementList (from.getDocumentElement (),
     2607              StaticStrings.COLLECTIONMETADATA_ELEMENT,
     2608              StaticStrings.NAME_ATTRIBUTE, att_values[i]);
     2609              // if such elements don't exist, don't bother
     2610              if (e_list == null) {
     2611                  continue;
     2612              }
     2613              for (int j=0; j<e_list.size (); j++) {
     2614                  Element e = (Element)e_list.get (j);
     2615                  if (e.getAttribute (StaticStrings.ASSIGNED_ATTRIBUTE).equals (StaticStrings.FALSE_STR)) {
     2616                      continue;
     2617                  }
     2618                  String text = XMLTools.getNodeText (e);
     2619                  String lang = e.getAttribute (StaticStrings.LANGUAGE_ATTRIBUTE);
     2620                 
     2621                  Element displayItem = constructElement (StaticStrings.DISPLAYITEM_STR, map_attrs[i],
     2622                  StaticStrings.LANG_STR, lang, text, to);
     2623                  displayItemList.appendChild (displayItem);
     2624              }
     2625             
     2626          }
     2627          destination.appendChild (displayItemList);
     2628    }
     2629    // This method creates a DisplayItem element of the type of 'to' by using the ingredients from the element 'e'
     2630    private Element constructDisplayItem (Element e, Document to) {
     2631        String lang_string = e.getAttribute (StaticStrings.LANGUAGE_ATTRIBUTE);
     2632        String text = XMLTools.getNodeText (e);
     2633        Element displayItem = to.createElement (StaticStrings.DISPLAYITEM_STR);
     2634        displayItem.setAttribute (StaticStrings.NAME_ATTRIBUTE, StaticStrings.NAME_ATTRIBUTE);
     2635        displayItem.setAttribute (StaticStrings.LANG_STR, lang_string);
     2636        XMLTools.setNodeText (displayItem, text);
     2637        return displayItem;
     2638    }
     2639    private void convertMetadataList (Document from, Document to) {
     2640        Element metadataList = to.createElement (StaticStrings.METADATALIST_STR);
     2641        Element destination = to.getDocumentElement ();
     2642       
     2643        String []ele_names =
     2644        {StaticStrings.COLLECTIONMETADATA_CREATOR_ELEMENT,
     2645         StaticStrings.COLLECTIONMETADATA_MAINTAINER_ELEMENT,
     2646         StaticStrings.COLLECTIONMETADATA_PUBLIC_ELEMENT};
     2647         String []att_names =
     2648         {StaticStrings.COLLECTIONMETADATA_CREATOR_STR,
     2649          StaticStrings.COLLECTIONMETADATA_MAINTAINER_STR,
     2650          StaticStrings.COLLECTIONMETADATA_PUBLIC_STR};
     2651          for (int i=0; i<ele_names.length; i++) {
     2652              Element e = XMLTools.getNamedElement (from.getDocumentElement (),
     2653              ele_names[i], StaticStrings.NAME_ATTRIBUTE, att_names[i]);
     2654              if (e == null) {
     2655                  continue;
     2656              }
     2657              String text = XMLTools.getNodeText (e);
     2658              Element metadata = to.createElement (StaticStrings.METADATA_STR);
     2659              metadata.setAttribute (StaticStrings.NAME_ATTRIBUTE, att_names[i]);
     2660              metadata.setAttribute (StaticStrings.LANG_STR, StaticStrings.ENGLISH_LANGUAGE_STR);
     2661              XMLTools.setNodeText (metadata, text);
     2662              metadataList.appendChild (metadata);
     2663          }
     2664
     2665          destination.appendChild (metadataList);
     2666    }
     2667    // This method creates an element with the name 'element_name' of the type of 'to' by using the other three strings
     2668    private Element constructElement (String element_name, String name_value, String lang_att, String lang_value, String text, Document to) {
     2669        Element e = to.createElement (element_name);
     2670        e.setAttribute (StaticStrings.ASSIGNED_ATTRIBUTE, StaticStrings.TRUE_STR);
     2671        e.setAttribute (StaticStrings.NAME_ATTRIBUTE, name_value);
     2672        e.setAttribute (lang_att, lang_value);
     2673        XMLTools.setNodeText (e, text);
     2674       
     2675        return e;
     2676    }
     2677    // Convert classify in the internal(i.e. Document from) to collectionconfig.xml (i.e. Document to)
     2678    private void convertClassifier (Document from, Document to) {
     2679        Element browse_element = to.createElement (StaticStrings.BROWSE_STR);
     2680        NodeList children = from.getDocumentElement ().getElementsByTagName (StaticStrings.CLASSIFY_ELEMENT);
     2681       
     2682        int num_children = (children == null)? 0 : children.getLength ();
     2683       
     2684        if (num_children == 0) {
     2685            return ;
     2686        }
     2687       
     2688        for (int i=0; i<num_children; i++) {
     2689           
     2690            Element child =  (Element)children.item (i);
     2691            if (child.getAttribute (StaticStrings.ASSIGNED_ATTRIBUTE).equals (StaticStrings.FALSE_STR)) {
     2692                continue;
     2693            }
     2694            String str = child.getAttribute (StaticStrings.TYPE_ATTRIBUTE);
     2695            Element classifier_element = to.createElement (StaticStrings.CLASSIFIER_STR);
     2696            classifier_element.setAttribute (StaticStrings.NAME_ATTRIBUTE, str);
     2697           
     2698            NodeList option_children = child.getElementsByTagName (StaticStrings.OPTION_ELEMENT);
     2699            for (int j=0; j<option_children.getLength (); j++) {
     2700                Element el = (Element)option_children.item (j);
     2701                if (el.getAttribute (StaticStrings.ASSIGNED_ATTRIBUTE).equals (StaticStrings.FALSE_STR)) {
     2702                    continue;
     2703                }
     2704                String name_str = el.getAttribute (StaticStrings.NAME_ATTRIBUTE);
     2705                String value_str = XMLTools.getNodeText (el);
     2706               
     2707               
     2708                if (name_str == null && value_str == null) {
     2709                    continue;
     2710                }
     2711                Element option_element = to.createElement (StaticStrings.OPTION_STR);
     2712                if (name_str != null && name_str.equals (StaticStrings.METADATA_STR)) {
     2713                   
     2714                    // The metadata argument is the fully qualified name of a metadata element, so if it contains a namespace, remove the extracted metadata namespace as the build process doesn't know about it.
     2715                    String[] values = value_str.split (StaticStrings.COMMA_CHARACTER);
     2716                    value_str = "";
     2717                    for (int k=0; k<=values.length-1; k++) {
     2718                        if(values[k].startsWith (StaticStrings.EXTRACTED_NAMESPACE)) {
     2719                            values[k] = values[k].substring (StaticStrings.EXTRACTED_NAMESPACE.length ());
     2720                        }
     2721                        else {
     2722                            MetadataElement metadata_element = MetadataTools.getMetadataElementWithDisplayName (values[k]);
     2723                            if (metadata_element != null) {
     2724                                values[k] = metadata_element.getFullName ();
     2725                            }
     2726                        }
     2727                        if (k < values.length-1) {
     2728                            value_str = value_str + values[k] + StaticStrings.COMMA_CHARACTER;
     2729                        } else {
     2730                            value_str = value_str + values[k];
     2731                        }
     2732                    }
     2733                }
     2734               
     2735                if (!name_str.equals ("")) {
     2736                    if (!name_str.startsWith (StaticStrings.MINUS_CHARACTER)) {
     2737                        name_str = StaticStrings.MINUS_CHARACTER + name_str;
     2738                    }
     2739                    option_element.setAttribute (StaticStrings.NAME_ATTRIBUTE, name_str);
     2740                }
     2741               
     2742                if (!value_str.equals ("")) {
     2743                    option_element.setAttribute (StaticStrings.VALUE_ATTRIBUTE, value_str);
     2744                }
     2745               
     2746                classifier_element.appendChild (option_element);
     2747            }
     2748           
     2749            //format element for this classifier
     2750            Element e = (Element)XMLTools.getChildByTagName (child, StaticStrings.FORMAT_STR);
     2751           
     2752            if (e != null) {
     2753                classifier_element.appendChild (convertFormat(to, e));
     2754            }
     2755            browse_element.appendChild (classifier_element);
     2756        }
     2757       
     2758        //convert default classifier format
     2759        Element e = XMLTools.getNamedElement (from.getDocumentElement (), StaticStrings.FORMAT_STR,
     2760                                                StaticStrings.NAME_ATTRIBUTE,  StaticStrings.BROWSE_STR);
     2761        browse_element.appendChild (convertFormat(to, e));
     2762       
     2763        to.getDocumentElement ().appendChild (browse_element);
     2764    }
     2765    private Element convertFormat(Document to, Element e) {
     2766        String format_str = XMLTools.getNodeText(e);
     2767        Element format = to.createElement (StaticStrings.FORMAT_STR);
     2768        //XMLTools.copyAllChildren (format, e);
     2769        XMLTools.setNodeText(format, format_str);
     2770        return format;
     2771    }
     2772    //convert format statement for search
     2773    private void convertSearchFormat (Document from, Document to) {
     2774        Element search = (Element)XMLTools.getChildByTagName (to.getDocumentElement (), StaticStrings.SEARCH_STR);
     2775        Element e = XMLTools.getNamedElement (from.getDocumentElement (), StaticStrings.FORMAT_STR,
     2776                                                StaticStrings.NAME_ATTRIBUTE,  StaticStrings.SEARCH_STR);
     2777                                               
     2778        search.appendChild (convertFormat(to, e));
     2779       
     2780    }
     2781    //convert format statement for display of the documents
     2782    private void convertDisplayFormat (Document from, Document to) {
     2783        Element e = XMLTools.getNamedElement (from.getDocumentElement (), StaticStrings.FORMAT_STR,
     2784                                                StaticStrings.NAME_ATTRIBUTE,  StaticStrings.DISPLAY_STR);
     2785        if (e == null) {
     2786            return;
     2787        }
     2788        Element display = to.createElement (StaticStrings.DISPLAY_STR);
     2789        display.appendChild (convertFormat(to, e));
     2790        to.getDocumentElement ().appendChild (display);
     2791    }
     2792    // Convert plugins in the internal(i.e. Document from) to collectionconfig.xml (i.e. Document to)
     2793    private void convertPlugin (Document from, Document to) {
     2794        Element import_element = to.createElement (StaticStrings.IMPORT_STR);
     2795        Element plugin_list_element = to.createElement (StaticStrings.PLUGINLIST_STR);
     2796       
     2797        NodeList children = from.getDocumentElement ().getElementsByTagName (StaticStrings.PLUGIN_ELEMENT);
     2798        int num_children = (children == null)? 0 : children.getLength ();
     2799        if (num_children == 0) {
     2800            return ;
     2801        }
     2802       
     2803        for (int i=0; i<num_children; i++) {
     2804           
     2805            Element child =  (Element)children.item (i);
     2806            if (child.getAttribute (StaticStrings.SEPARATOR_ATTRIBUTE).equals (StaticStrings.TRUE_STR)) {
     2807                continue;
     2808            }
     2809            if (child.getAttribute (StaticStrings.ASSIGNED_ATTRIBUTE).equals (StaticStrings.FALSE_STR)) {
     2810                continue;
     2811            }
     2812           
     2813            String str = child.getAttribute (StaticStrings.TYPE_ATTRIBUTE);
     2814            Element plugin_element = to.createElement (StaticStrings.PLUGIN_STR);
     2815            plugin_element.setAttribute (StaticStrings.NAME_ATTRIBUTE, str);
     2816           
     2817            NodeList option_children = child.getElementsByTagName (StaticStrings.OPTION_ELEMENT);
     2818            for (int j=0; j<option_children.getLength (); j++) {
     2819                Element el = (Element)option_children.item (j);
     2820                if(!el.getAttribute (StaticStrings.ASSIGNED_ATTRIBUTE).equals (StaticStrings.TRUE_STR)) {
     2821                    continue;
     2822                }
     2823                String name_str = el.getAttribute (StaticStrings.NAME_ATTRIBUTE);
     2824                String value_str = XMLTools.getNodeText (el);
     2825               
     2826               
     2827                if (name_str == null && value_str == null) {
     2828                    continue;
     2829                }
     2830                Element option_element = to.createElement (StaticStrings.OPTION_STR);
     2831                if (name_str != null && name_str.equals (StaticStrings.METADATA_STR)) {
     2832                   
     2833                    // The metadata argument is the fully qualified name of a metadata element, so if it contains a namespace, remove the extracted metadata namespace as the build process doesn't know about it.
     2834                    String[] values = value_str.split (StaticStrings.COMMA_CHARACTER);
     2835                    value_str = "";
     2836                    for (int k=0; k<=values.length-1; k++) {
     2837                        if(values[k].startsWith (StaticStrings.EXTRACTED_NAMESPACE)) {
     2838                            values[k] = values[k].substring (StaticStrings.EXTRACTED_NAMESPACE.length ());
     2839                        }
     2840
     2841                        if (k < values.length-1) {
     2842                            value_str = value_str + values[k] + StaticStrings.COMMA_CHARACTER;
     2843                        } else {
     2844                            value_str = value_str + values[k];
     2845                        }
     2846                    }
     2847                }
     2848               
     2849                if (!name_str.equals ("")) {
     2850                    if (!name_str.startsWith (StaticStrings.MINUS_CHARACTER)) {
     2851                        name_str = StaticStrings.MINUS_CHARACTER + name_str;
     2852                    }
     2853                    option_element.setAttribute (StaticStrings.NAME_ATTRIBUTE, name_str);
     2854                }
     2855               
     2856                if (!value_str.equals ("")) {
     2857                    option_element.setAttribute (StaticStrings.VALUE_ATTRIBUTE, value_str);
     2858                }
     2859               
     2860                plugin_element.appendChild (option_element);
     2861            }//for loop ends
     2862           
     2863            plugin_list_element.appendChild (plugin_element);
     2864        }//for loop ends
     2865       
     2866        import_element.appendChild (plugin_list_element);
     2867        to.getDocumentElement ().appendChild (import_element);
     2868    }
     2869    //Handle 'searchType' of collectionConfig.xml. In the internal structure, its also called 'searchType', eg. plain, form
     2870    private void convertSearchType (Document from, Document to) {
     2871        Element e = XMLTools.getNamedElement (from.getDocumentElement (), StaticStrings.FORMAT_STR,
     2872                StaticStrings.NAME_ATTRIBUTE,  StaticStrings.SEARCHTYPE_ELEMENT);//searchType
     2873       
     2874        if (e == null) {
     2875            return;
     2876        }
     2877        Element search_type_element = to.createElement (StaticStrings.FORMAT_STR);
     2878       
     2879//        String searchtype_str = e.getAttribute (StaticStrings.VALUE_ATTRIBUTE);       
     2880//        search_type_element.setAttribute (StaticStrings.VALUE_ATTRIBUTE, searchtype_str);
     2881        String searchtype_str = XMLTools.getNodeText(e);       
     2882        XMLTools.setNodeText(search_type_element, searchtype_str);
     2883       
     2884        search_type_element.setAttribute (StaticStrings.NAME_ATTRIBUTE, StaticStrings.SEARCHTYPE_ELEMENT);
     2885        //Get the 'search' element from 'to'
     2886        Element search = (Element)XMLTools.getChildByTagName (to.getDocumentElement (), StaticStrings.SEARCH_STR);
     2887        search.appendChild (search_type_element);
     2888    }
     2889   
     2890    private void convertBuildType (Document from, Document to) {
     2891        Element e = XMLTools.getNamedElement (from.getDocumentElement (),
     2892        StaticStrings.BUILDTYPE_ELEMENT,
     2893        StaticStrings.NAME_ATTRIBUTE, StaticStrings.BUILDTYPE_STR);
     2894        if (e == null) {
     2895            return;
     2896        }
     2897        String indexer = XMLTools.getNodeText (e);
     2898        Element search = to.createElement (StaticStrings.SEARCH_STR);
     2899        search.setAttribute (StaticStrings.TYPE_ATTRIBUTE, indexer);
     2900        to.getDocumentElement ().appendChild (search);
     2901    }
     2902    private void convertDefaultIndex (Document from, Document to, Element search) {
     2903        Element source = from.getDocumentElement ();
     2904       
     2905        Element default_index_element = (Element)XMLTools.getChildByTagName (source, StaticStrings.INDEX_DEFAULT_ELEMENT);
     2906        if (default_index_element == null) {
     2907            return;
     2908        }
     2909       
     2910        String indexer = search.getAttribute (StaticStrings.TYPE_ATTRIBUTE);
     2911        String level_str = default_index_element.getAttribute (StaticStrings.LEVEL_ATTRIBUTE);
     2912        // Debugging purposes
     2913        if (level_str.equals ("") && indexer.equals (StaticStrings.MG_STR) ) {
     2914            System.out.println ("Bug: DefaultIndex should have its level attribute not empty.");
     2915        }
     2916       
     2917        NodeList content_elements = default_index_element.getElementsByTagName (StaticStrings.CONTENT_ELEMENT);
     2918        int content_elements_length = content_elements.getLength ();
     2919       
     2920        // Don't output anything if no indexes are set
     2921        if(content_elements_length == 0) {
     2922            return ;//
     2923        }
     2924       
     2925        String index_str = "";
     2926       
     2927        if (indexer.equals (StaticStrings.MG_STR)) {
     2928            //combine level with indexes
     2929            index_str = level_str + StaticStrings.COLON_CHARACTER;
     2930        }
     2931        else { //for mgpp/lucene, just take index
     2932            //do nothing
     2933        }
     2934       
     2935        for(int k = 0; k < content_elements_length; k++) {
     2936            Element content_element = (Element) content_elements.item (k);
     2937            if (content_element.getAttribute (StaticStrings.ASSIGNED_ATTRIBUTE).equals (StaticStrings.FALSE_STR)) {
     2938                continue;
     2939            }
     2940            String name_str = content_element.getAttribute (StaticStrings.NAME_ATTRIBUTE);
     2941           
     2942            if(name_str.startsWith (StaticStrings.EXTRACTED_NAMESPACE)) {
     2943                name_str = name_str.substring (StaticStrings.EXTRACTED_NAMESPACE.length ());
     2944            }
     2945
     2946            index_str = index_str + name_str;
     2947           
     2948            // Make it comma separated string
     2949            if(k < content_elements_length - 1) {
     2950                index_str = index_str + StaticStrings.COMMA_CHARACTER;
     2951            }
     2952            content_element = null;
     2953        }//for loop ends
     2954       
     2955       
     2956        Element default_index = to.createElement (StaticStrings.INDEX_DEFAULT_ELEMENT_LOWERCASE);
     2957        default_index.setAttribute (StaticStrings.NAME_ATTRIBUTE, index_str);
     2958        search.appendChild (default_index);
     2959       
     2960    }
     2961    private void convertSubcollection (Document from, Document to) {
     2962        Element source = from.getDocumentElement ();
     2963        //Get the 'search' element from 'to' which has already been created in 'convertBuildType'
     2964        Element search = (Element)XMLTools.getChildByTagName (to.getDocumentElement (), StaticStrings.SEARCH_STR);
     2965       
     2966        // Get the Subcollection element from the internal structure
     2967        NodeList subcollection_elements = source.getElementsByTagName (StaticStrings.SUBCOLLECTION_ELEMENT);
     2968        if (subcollection_elements == null) {
     2969            return;
     2970        }
     2971        int subcollection_elements_length = subcollection_elements.getLength ();
     2972       
     2973        if (subcollection_elements_length == 0) { // no
     2974            return ;
     2975        }
     2976       
     2977        for(int j = 0; j < subcollection_elements_length; j++) {
     2978           
     2979            Element e = (Element) subcollection_elements.item (j);
     2980            if (e.getAttribute (StaticStrings.ASSIGNED_ATTRIBUTE).equals (StaticStrings.FALSE_STR)) {
     2981                continue;
     2982            }
     2983            String content = e.getAttribute (StaticStrings.CONTENT_ATTRIBUTE);
     2984            String name = e.getAttribute (StaticStrings.NAME_ATTRIBUTE);
     2985            String options = e.getAttribute (StaticStrings.OPTIONS_ATTRIBUTE);
     2986            String type = e.getAttribute (StaticStrings.TYPE_ATTRIBUTE);
     2987            String text = XMLTools.getNodeText (e);
     2988           
     2989            String filter = "";
     2990            if (type.equals (StaticStrings.EXCLUDE_STR)) {
     2991                filter = StaticStrings.EXCLAMATION_CHARACTER;
     2992            }
     2993           
     2994            if(content.startsWith (StaticStrings.EXTRACTED_NAMESPACE)) {
     2995                content = content.substring (StaticStrings.EXTRACTED_NAMESPACE.length ());
     2996            }
     2997            filter = filter + content + StaticStrings.SEPARATOR_CHARACTER + text;
     2998            if (options != null && options != "") {
     2999                filter = filter + StaticStrings.SEPARATOR_CHARACTER + options;
     3000            }
     3001            Element subcollection = to.createElement (StaticStrings.SUBCOLLECTION_STR);
     3002            subcollection.setAttribute (StaticStrings.FILTER_ATTRIBUTE, filter);
     3003            subcollection.setAttribute (StaticStrings.NAME_ATTRIBUTE, name);
     3004           
     3005            search.appendChild (subcollection);
     3006        }
     3007    }
     3008    private void convertSubcollectionIndexes (Document from, Document to) {
     3009        Element source = from.getDocumentElement ();
     3010        //Get the 'search' element from 'to' which has already been created in 'convertBuildType'
     3011        Element search = (Element)XMLTools.getChildByTagName (to.getDocumentElement (), StaticStrings.SEARCH_STR);
     3012       
     3013        // Get the SubcollectionIndexes element from the internal structure
     3014        Element subcollection_indexes = (Element)XMLTools.getChildByTagName (source, StaticStrings.SUBCOLLECTION_INDEXES_ELEMENT);
     3015        if (subcollection_indexes == null) {
     3016            return;
     3017        }
     3018        NodeList index_elements = subcollection_indexes.getElementsByTagName (StaticStrings.INDEX_ELEMENT);
     3019        int index_elements_length = index_elements.getLength ();
     3020       
     3021        if (index_elements_length == 0) { // no indexes
     3022            return ;
     3023        }
     3024       
     3025        for(int j = 0; j < index_elements_length; j++) {
     3026            Element index_element = (Element) index_elements.item (j);
     3027            if (index_element.getAttribute (StaticStrings.ASSIGNED_ATTRIBUTE).equals (StaticStrings.FALSE_STR)) {
     3028                continue;
     3029            }
     3030           
     3031            Element index = to.createElement (StaticStrings.SUBCOLLECTION_INDEX_ELEMENT);
     3032           
     3033            String index_value = "";
     3034           
     3035            NodeList content_elements = index_element.getElementsByTagName (StaticStrings.CONTENT_ELEMENT);
     3036            int content_elements_length = content_elements.getLength ();
     3037           
     3038            for(int k = 0; k < content_elements_length; k++) {
     3039                Element content_element = (Element) content_elements.item (k);
     3040                if (content_element.getAttribute (StaticStrings.ASSIGNED_ATTRIBUTE).equals (StaticStrings.FALSE_STR)) {
     3041                    continue;
     3042                }
     3043                String name_str = content_element.getAttribute (StaticStrings.NAME_ATTRIBUTE);
     3044                index_value += name_str;
     3045                // Make it comma separated string
     3046                if(k < content_elements_length - 1) {
     3047                    index_value += StaticStrings.COMMA_CHARACTER;
     3048                }
     3049                content_element = null;
     3050            }//for loop ends
     3051           
     3052            index.setAttribute (StaticStrings.NAME_ATTRIBUTE, index_value);
     3053           
     3054            // Now constructing 'displayItem' element for this 'indexSubcollection' element
     3055            // from the collectionmetadata element
     3056            ArrayList collectionmetadata_list = XMLTools.getNamedElementList (source,
     3057            StaticStrings.COLLECTIONMETADATA_ELEMENT,
     3058            StaticStrings.NAME_ATTRIBUTE, index_value);
     3059           
     3060            if (collectionmetadata_list == null) {
     3061                //try adding the "." prefix
     3062                index_value = StaticStrings.DOT_CHARACTER + index_value;
     3063                collectionmetadata_list = XMLTools.getNamedElementList (source,
     3064                StaticStrings.COLLECTIONMETADATA_ELEMENT,
     3065                StaticStrings.NAME_ATTRIBUTE, index_value);
     3066            }
     3067            if (collectionmetadata_list != null) {
     3068               
     3069                for(int k = 0; k < collectionmetadata_list.size (); k++) {
     3070                    Element collectionmetadata = (Element)collectionmetadata_list.get (k);
     3071                    if (collectionmetadata.getAttribute (StaticStrings.ASSIGNED_ATTRIBUTE).equals (StaticStrings.FALSE_STR)) {
     3072                        continue;
     3073                    }
     3074                    Element displayItem = constructDisplayItem (collectionmetadata, to);
     3075                    index.appendChild (displayItem);
     3076                }
     3077            }
     3078           
     3079            search.appendChild (index);
     3080           
     3081        } //for loop ends
     3082    }
     3083   
     3084    private void convertLanguages (Document from, Document to) {
     3085        Element source = from.getDocumentElement ();
     3086        //Get the 'search' element from 'to' which has already been created in 'convertBuildType'
     3087        Element search = (Element)XMLTools.getChildByTagName (to.getDocumentElement (), StaticStrings.SEARCH_STR);
     3088       
     3089        // Get the Languages element from the internal structure
     3090        Element languages = (Element)XMLTools.getChildByTagName (source, StaticStrings.LANGUAGES_ELEMENT);
     3091        if (languages == null) {
     3092            return;
     3093        }
     3094        NodeList language_elements = languages.getElementsByTagName (StaticStrings.LANGUAGE_ELEMENT);
     3095        int language_elements_length = language_elements.getLength ();
     3096       
     3097        if (language_elements_length == 0) {
     3098            return ;
     3099        }
     3100       
     3101        for(int j = 0; j < language_elements_length; j++) {
     3102            Element element = (Element) language_elements.item (j);
     3103            if (element.getAttribute (StaticStrings.ASSIGNED_ATTRIBUTE).equals (StaticStrings.FALSE_STR)) {
     3104                continue;
     3105            }
     3106           
     3107            // Create indexLanguage element
     3108            Element index_language = to.createElement (StaticStrings.LANGUAGE_INDEX_ELEMENT);
     3109           
     3110            String name_str = element.getAttribute (StaticStrings.NAME_ATTRIBUTE);
     3111            index_language.setAttribute (StaticStrings.NAME_ATTRIBUTE, name_str);
     3112           
     3113            // Now constructing 'displayItem' element for this 'indexLanguage' element
     3114            // from the collectionmetadata element
     3115            ArrayList collectionmetadata_list = XMLTools.getNamedElementList (source,
     3116            StaticStrings.COLLECTIONMETADATA_ELEMENT,
     3117            StaticStrings.NAME_ATTRIBUTE, name_str);
     3118           
     3119            if (collectionmetadata_list == null) {
     3120                //try adding the "." prefix
     3121                name_str = StaticStrings.DOT_CHARACTER + name_str;
     3122                collectionmetadata_list = XMLTools.getNamedElementList (source,
     3123                StaticStrings.COLLECTIONMETADATA_ELEMENT,
     3124                StaticStrings.NAME_ATTRIBUTE, name_str);
     3125            }
     3126            if (collectionmetadata_list != null) {
     3127               
     3128                for(int k = 0; k < collectionmetadata_list.size (); k++) {
     3129                    Element collectionmetadata = (Element)collectionmetadata_list.get (k);
     3130                    if (collectionmetadata.getAttribute (StaticStrings.ASSIGNED_ATTRIBUTE).equals (StaticStrings.FALSE_STR)) {
     3131                        continue;
     3132                    }
     3133                    Element displayItem = constructDisplayItem (collectionmetadata, to);
     3134                    index_language.appendChild (displayItem);
     3135                }
     3136            }
     3137           
     3138            search.appendChild (index_language);
     3139           
     3140        } //for loop ends
     3141       
     3142        // Convert DefaultLanguage
     3143        // Get the DefaultLanguage element from the internal structure
     3144        Element default_language = (Element)XMLTools.getChildByTagName (source, StaticStrings.LANGUAGE_DEFAULT_ELEMENT);
     3145        if(default_language != null) {
     3146            String lang_name = default_language.getAttribute (StaticStrings.NAME_ATTRIBUTE);
     3147            Element default_index_language = to.createElement (StaticStrings.LANGUAGE_DEFAULT_INDEX_ELEMENT);
     3148            default_index_language.setAttribute (StaticStrings.NAME_ATTRIBUTE, lang_name);
     3149            search.appendChild (default_index_language);
     3150        }
     3151        // Convert LanguageMetadata
     3152        // Get the LanguageMetadata element from the internal structure
     3153        Element language_metadata = (Element)XMLTools.getChildByTagName (source, StaticStrings.LANGUAGE_METADATA_ELEMENT);
     3154        if(language_metadata != null) {
     3155            String meta_name = language_metadata.getAttribute (StaticStrings.NAME_ATTRIBUTE);
     3156            Element language_meta = to.createElement (StaticStrings.LANGUAGE_METADATA_ELEMENT_STR);
     3157            if(meta_name.startsWith (StaticStrings.EXTRACTED_NAMESPACE)) {
     3158                meta_name = meta_name.substring (StaticStrings.EXTRACTED_NAMESPACE.length ());
     3159            }
     3160            language_meta.setAttribute (StaticStrings.NAME_ATTRIBUTE, meta_name);
     3161            search.appendChild (language_meta);
     3162        }
     3163    }
     3164   
     3165    //convert indexes and their displayItems, which go in 'search' element in collectionConfig.xml
     3166    //parameter 'to' is the document to be saved as collectionConfig.xml
     3167    //parameter 'from' is the internal xml structure
     3168    private void convertIndex (Document from, Document to) {
     3169        Element source = from.getDocumentElement ();
     3170        //Get the 'search' element from 'to' which has already been created in 'convertBuildType'
     3171        Element search = (Element)XMLTools.getChildByTagName (to.getDocumentElement (), StaticStrings.SEARCH_STR);
     3172       
     3173        //THere are two sets of indexes elements, find the one which is assigned 'true'
     3174        Element indexes = XMLTools.getNamedElement (source,
     3175        StaticStrings.INDEXES_ELEMENT,
     3176        StaticStrings.ASSIGNED_ATTRIBUTE, StaticStrings.TRUE_STR);
     3177        if (indexes == null) {
     3178            return;
     3179        }
     3180        NodeList index_elements = indexes.getElementsByTagName (StaticStrings.INDEX_ELEMENT);
     3181        int index_elements_length = index_elements.getLength ();
     3182       
     3183        if (index_elements_length == 0) { // no indexes
     3184            return ;
     3185        }
     3186       
     3187        //find out it's mg or mgpp/lucene
     3188        String mg = search.getAttribute (StaticStrings.TYPE_ATTRIBUTE);
     3189        boolean mg_indexer = false;
     3190        if (mg.equals (StaticStrings.MG_STR)) {
     3191            mg_indexer = true;//it's mg, then the level is set as attribute of
     3192        }
     3193        if (mg_indexer == false) {
     3194            // It's mgpp. Construct 'level' and 'defaultLevel' elements separately.
     3195            convertLevels (from, to, search);
     3196        }
     3197       
     3198        for(int j = 0; j < index_elements_length; j++) {
     3199            Element index_element = (Element) index_elements.item (j);
     3200            if (index_element.getAttribute (StaticStrings.ASSIGNED_ATTRIBUTE).equals (StaticStrings.FALSE_STR)) {
     3201                continue;
     3202            }
     3203           
     3204            Element index_ele = to.createElement (StaticStrings.INDEX_LOW_STR);//index
     3205           
     3206            // Used for creating displayItem for this element 'index_ele' further below
     3207            // full_index_names contain 'ex.'
     3208            String full_index_name = "";
     3209            String level_str = "";
     3210           
     3211            StringBuffer index_value = new StringBuffer ();
     3212            if (mg_indexer == true) {
     3213                // For mg indexer, there is a 'level' attribute in the index element of the internal structure
     3214                // But mgpp/lucene don't
     3215                level_str = index_element.getAttribute (StaticStrings.LEVEL_ATTRIBUTE);
     3216                if(level_str.length () > 0) {
     3217                    index_value.append (level_str).append (StaticStrings.COLON_CHARACTER);
     3218                    //index_value = index_value.StaticStrings.COLON_CHARACTER;
     3219                }
     3220            }
     3221           
     3222            NodeList content_elements = index_element.getElementsByTagName (StaticStrings.CONTENT_ELEMENT);
     3223            int content_elements_length = content_elements.getLength ();
     3224           
     3225            for(int k = 0; k < content_elements_length; k++) {
     3226                Element content_element = (Element) content_elements.item (k);
     3227                if (content_element.getAttribute (StaticStrings.ASSIGNED_ATTRIBUTE).equals (StaticStrings.FALSE_STR)) {
     3228                    continue;
     3229                }
     3230                String name_str = content_element.getAttribute (StaticStrings.NAME_ATTRIBUTE);
     3231               
     3232                full_index_name = full_index_name + name_str;
     3233                if (k < content_elements_length - 1) {
     3234                    full_index_name = full_index_name + StaticStrings.COMMA_CHARACTER;
     3235                }
     3236               
     3237                if(name_str.startsWith (StaticStrings.EXTRACTED_NAMESPACE)) {
     3238                    name_str = name_str.substring (StaticStrings.EXTRACTED_NAMESPACE.length ());
     3239                }
     3240
     3241                index_value.append (name_str);
     3242                name_str = null;
     3243                // Make it comma separated string
     3244                if(k < content_elements_length - 1) {
     3245                    index_value.append (StaticStrings.COMMA_CHARACTER);
     3246                }
     3247                content_element = null;
     3248            }//for loop ends
     3249           
     3250            String temp_str = index_value.toString ();
     3251            index_ele.setAttribute (StaticStrings.NAME_ATTRIBUTE, temp_str);
     3252           
     3253            // Now constructing 'displayItem' element for this 'index_ele' element
     3254            // The index names in the collectionmetadata elements in the internal structure are not the names that
     3255            // are used in the content elements (i.e. ex.Source or dc.Subject and keywords), but the names that are
     3256            // in the configuration files (i.e. Source or dc.Subject)
     3257            ArrayList collectionmetadata_list = XMLTools.getNamedElementList (source,
     3258            StaticStrings.COLLECTIONMETADATA_ELEMENT,
     3259            StaticStrings.NAME_ATTRIBUTE, temp_str);
     3260           
     3261            if (collectionmetadata_list == null) {
     3262                //try adding the "." prefix
     3263                String with_dot_str = StaticStrings.DOT_CHARACTER + temp_str;
     3264                collectionmetadata_list = XMLTools.getNamedElementList (source,
     3265                StaticStrings.COLLECTIONMETADATA_ELEMENT,
     3266                StaticStrings.NAME_ATTRIBUTE, with_dot_str);
     3267               
     3268                if (collectionmetadata_list == null) {
     3269                    //try the full name, i.e. with 'ex.'
     3270                    if (mg_indexer == true) {
     3271                        full_index_name = level_str+StaticStrings.COLON_CHARACTER+full_index_name;
     3272                    }
     3273                    collectionmetadata_list = XMLTools.getNamedElementList (source,
     3274                    StaticStrings.COLLECTIONMETADATA_ELEMENT,
     3275                    StaticStrings.NAME_ATTRIBUTE, full_index_name);
     3276                }
     3277                if (collectionmetadata_list == null) {
     3278                    with_dot_str = StaticStrings.DOT_CHARACTER + full_index_name;
     3279                    collectionmetadata_list = XMLTools.getNamedElementList (source,
     3280                    StaticStrings.COLLECTIONMETADATA_ELEMENT,
     3281                    StaticStrings.NAME_ATTRIBUTE, with_dot_str);
     3282                }
     3283            }
     3284            if (collectionmetadata_list != null) {
     3285               
     3286                for(int k = 0; k < collectionmetadata_list.size (); k++) {
     3287                    Element collectionmetadata = (Element)collectionmetadata_list.get (k);
     3288                    if (collectionmetadata.getAttribute (StaticStrings.ASSIGNED_ATTRIBUTE).equals (StaticStrings.FALSE_STR)) {
     3289                        continue;
     3290                    }
     3291                    Element displayItem = constructDisplayItem (collectionmetadata, to);
     3292                   
     3293                    index_ele.appendChild (displayItem);
     3294                }
     3295            }
     3296           
     3297            search.appendChild (index_ele);
     3298           
     3299        } //for loop ends
     3300       
     3301        //Convert default index
     3302        convertDefaultIndex (from, to, search);
     3303    }
     3304    // Convert levels for mgpp/lucene. This method is called by converIndex() when mgpp indexer is detected.
     3305    private void convertLevels (Document from, Document to, Element search) {
     3306        Element source = from.getDocumentElement ();
     3307        Element index_option = XMLTools.getNamedElement (source,
     3308        StaticStrings.INDEXOPTIONS_ELEMENT,
     3309        StaticStrings.NAME_ATTRIBUTE, StaticStrings.LEVELS_STR);
     3310        if (index_option == null) {
     3311            return;
     3312        }
     3313        //Debugging purposes
     3314        if (index_option.getAttribute (StaticStrings.ASSIGNED_ATTRIBUTE).equals (StaticStrings.FALSE_STR)) {
     3315            DebugStream.println ("For mgpp, there should be an IndexOption element for levels which is assigned 'true': possible bug.");
     3316        }
     3317       
     3318        NodeList option_elements = index_option.getElementsByTagName (StaticStrings.OPTION_ELEMENT);
     3319        int num_elements = option_elements.getLength ();
     3320       
     3321        // Don't output anything if no indexes are set
     3322        if(num_elements == 0) {
     3323            return ;//
     3324        }
     3325       
     3326        for(int k = 0; k < num_elements; k++) {
     3327            Element e = (Element) option_elements.item (k);
     3328            String name_str = e.getAttribute (StaticStrings.NAME_ATTRIBUTE);
     3329            Element level_element = to.createElement (StaticStrings.LEVEL_ELEMENT);
     3330            level_element.setAttribute (StaticStrings.NAME_ATTRIBUTE, name_str);
     3331           
     3332            //Now construct displayItem for this level element from collectionmetadata
     3333            ArrayList collectionmetadata_list = XMLTools.getNamedElementList (source,
     3334            StaticStrings.COLLECTIONMETADATA_ELEMENT,
     3335            StaticStrings.NAME_ATTRIBUTE, name_str);
     3336           
     3337            if (collectionmetadata_list == null) {
     3338                //try adding the "." prefix
     3339                name_str = StaticStrings.DOT_CHARACTER + name_str;
     3340                collectionmetadata_list = XMLTools.getNamedElementList (source,
     3341                StaticStrings.COLLECTIONMETADATA_ELEMENT,
     3342                StaticStrings.NAME_ATTRIBUTE, name_str);
     3343            }
     3344            if (collectionmetadata_list != null) {
     3345               
     3346                for(int j = 0; j < collectionmetadata_list.size (); j++) {
     3347                    Element collectionmetadata = (Element)collectionmetadata_list.get (j);
     3348                   
     3349                    Element displayItem = constructDisplayItem (collectionmetadata, to);
     3350                    level_element.appendChild (displayItem);
     3351                }
     3352            }
     3353            search.appendChild (level_element);
     3354        }
     3355       
     3356        //Convert default level
     3357        Element default_index_option = XMLTools.getNamedElement (source,
     3358        StaticStrings.INDEXOPTION_DEFAULT_ELEMENT,
     3359        StaticStrings.NAME_ATTRIBUTE, StaticStrings.LEVEL_DEFAULT_STR);
     3360        if (default_index_option == null) {
     3361            return;
     3362        }
     3363        Element default_level = to.createElement (StaticStrings.LEVEL_DEFAULT_ELEMENT);
     3364        String default_level_str = default_index_option.getAttribute (StaticStrings.VALUE_ATTRIBUTE);
     3365        default_level.setAttribute (StaticStrings.NAME_ATTRIBUTE, default_level_str);
     3366        search.appendChild (default_level);
     3367       
     3368    }
     3369    // Append the element son to the element mother in the appropriate position.
     3370    static public void appendProperly (Element mother, Element son) {
     3371        if (son == null)
     3372            return;
     3373       
     3374        Node reference_node = findInsertionPoint (mother, son);
     3375        if(reference_node != null) {
     3376            mother.insertBefore (son, reference_node);
     3377        }
     3378        else {
     3379            mother.appendChild (son);
     3380        }
     3381    }
     3382    /** Find the best insertion position for the given DOM Element 'target_element' in the DOM Element 'document_element'. This should try to match command tag, and if found should then try to group by name or type (eg CollectionMeta), or append to end is no such grouping exists (eg Plugins). Failing a command match it will check against the command order for the best insertion location.
     3383     * @param target_element the command Element to be inserted
     3384     * @return the Element which the given command should be inserted before, or null to append to end of list
     3385     */
     3386    static public Node findInsertionPoint (Element document_element, Element target_element) {
     3387        ///ystem.err.println("Find insertion point: " + target_element.getNodeName());
     3388        String target_element_name = target_element.getNodeName ();
     3389       
     3390        // Try to find commands with the same tag.
     3391        NodeList matching_elements = document_element.getElementsByTagName (target_element_name);
     3392        // If we found matching elements, then we have our most likely insertion location, so check within for groupings
     3393        if(matching_elements.getLength () != 0) {
     3394            ///ystem.err.println("Found matching elements.");
     3395            // Only CollectionMeta are grouped.
     3396            if(target_element_name.equals (StaticStrings.COLLECTIONMETADATA_ELEMENT)) {
     3397                ///ystem.err.println("Dealing with collection metadata");
     3398                // Special case: CollectionMeta can be added at either the start or end of a collection configuration file. However the start position is reserved for special metadata, so if no non-special metadata can be found we must append to the end.
     3399                // So if the command to be added is special add it immediately after any other special command
     3400                if(target_element.getAttribute (StaticStrings.SPECIAL_ATTRIBUTE).equals (StaticStrings.TRUE_STR)) {
     3401                    int index = 0;
     3402                    Element matched_element = (Element) matching_elements.item (index);
     3403                    Element sibling_element = (Element) matched_element.getNextSibling ();
     3404                    while(sibling_element.getAttribute (StaticStrings.SPECIAL_ATTRIBUTE).equals (StaticStrings.TRUE_STR)) {
     3405                        index++;
     3406                        matched_element = (Element) matching_elements.item (index);
     3407                        sibling_element = (Element) matched_element.getNextSibling ();
     3408                    }
     3409                    if(sibling_element.getNodeName ().equals (NEWLINE_ELEMENT)) {
     3410                        Element newline_element = document.createElement (NEWLINE_ELEMENT);
     3411                        document_element.insertBefore (newline_element, sibling_element);
     3412                    }
     3413                    return sibling_element;
     3414                }
     3415                // Otherwise try to find a matching 'name' and add after the last one in that group.
     3416                else {
     3417                    int index = 0;
     3418                    target_element_name = target_element.getAttribute (StaticStrings.NAME_ATTRIBUTE);
     3419                    boolean found = false;
     3420                    // Skip all of the special metadata
     3421                    Element matched_element = (Element) matching_elements.item (index);
     3422                    while(matched_element.getAttribute (StaticStrings.SPECIAL_ATTRIBUTE).equals (StaticStrings.TRUE_STR)) {
     3423                        index++;
     3424                        matched_element = (Element) matching_elements.item (index);
     3425                    }
     3426                    // Begin search
     3427                    while(!found && matched_element != null) {
     3428                        if(matched_element.getAttribute (StaticStrings.NAME_ATTRIBUTE).equals (target_element_name)) {
     3429                            found = true;
     3430                        }
     3431                        else {
     3432                            index++;
     3433                            matched_element = (Element) matching_elements.item (index);
     3434                        }
     3435                    }
     3436                    // If we found a match, we need to continue checking until we find the last name match.
     3437                    if(found) {
     3438                        index++;
     3439                        Element previous_sibling = matched_element;
     3440                        Element sibling_element = (Element) matching_elements.item (index);
     3441                        while(sibling_element != null && sibling_element.getAttribute (StaticStrings.NAME_ATTRIBUTE).equals (target_element_name)) {
     3442                            previous_sibling = sibling_element;
     3443                            index++;
     3444                            sibling_element = (Element) matching_elements.item (index);
     3445                        }
     3446                        // Previous sibling now holds the command immediately before where we want to add, so find its next sibling and add to that. In this one case we can ignore new lines!
     3447                        return previous_sibling.getNextSibling ();
     3448                    }
     3449                    // If not found we just add after last metadata element
     3450                    else {
     3451                        Element last_element = (Element) matching_elements.item (matching_elements.getLength () - 1);
     3452                        return last_element.getNextSibling ();
     3453                    }
     3454                }
     3455               
     3456            }
     3457            else {
     3458                ///ystem.err.println("Not dealing with collection meta.");
     3459                Element matched_element = (Element) matching_elements.item (matching_elements.getLength () - 1);
     3460                // One final quick test. If the matched element is immediately followed by a NewLine command, then we insert another NewLine after the matched command, then return the NewLine instead (thus the about to be inserted command will be placed between the two NewLines)
     3461                Node sibling_element = matched_element.getNextSibling ();
     3462                if(sibling_element != null && sibling_element.getNodeName ().equals (NEWLINE_ELEMENT)) {
     3463                    Element newline_element = document.createElement (NEWLINE_ELEMENT);
     3464                    document_element.insertBefore (newline_element, sibling_element);
     3465                }
     3466                return sibling_element; // Note that this may be null
     3467            }
     3468        }
     3469        ///ystem.err.println("No matching elements found.");
     3470        // Locate where this command is in the ordering
     3471        int command_index = -1;
     3472        for(int i = 0; command_index == -1 && i < COMMAND_ORDER.length; i++) {
     3473            if(COMMAND_ORDER[i].equals (target_element_name)) {
     3474                command_index = i;
     3475            }
     3476        }
     3477        ///ystem.err.println("Command index is: " + command_index);
     3478        // Now move forward, checking for existing elements in each of the preceeding command orders.
     3479        int preceeding_index = command_index - 1;
     3480        ///ystem.err.println("Searching before the target command.");
     3481        while(preceeding_index >= 0) {
     3482            matching_elements = document_element.getElementsByTagName (COMMAND_ORDER[preceeding_index]);
     3483            // If we've found a match
     3484            if(matching_elements.getLength () > 0) {
     3485                // We add after the last element
     3486                Element matched_element = (Element) matching_elements.item (matching_elements.getLength () - 1);
     3487                // One final quick test. If the matched element is immediately followed by a NewLine command, then we insert another NewLine after the matched command, then return the NewLine instead (thus the about to be inserted command will be placed between the two NewLines)
     3488                Node sibling_element = matched_element.getNextSibling ();
     3489                if(sibling_element != null && sibling_element.getNodeName ().equals (NEWLINE_ELEMENT)) {
     3490                    Element newline_element = document.createElement (NEWLINE_ELEMENT);
     3491                    document_element.insertBefore (newline_element, sibling_element);
     3492                }
     3493                return sibling_element; // Note that this may be null
     3494            }
     3495            preceeding_index--;
     3496        }
     3497        // If all that fails, we now move backwards through the commands
     3498        int susceeding_index = command_index + 1;
     3499        ///ystem.err.println("Searching after the target command.");
     3500        while(susceeding_index < COMMAND_ORDER.length) {
     3501            matching_elements = document_element.getElementsByTagName (COMMAND_ORDER[susceeding_index]);
     3502            // If we've found a match
     3503            if(matching_elements.getLength () > 0) {
     3504                // We add before the first element
     3505                Element matched_element = (Element) matching_elements.item (0);
     3506                // One final quick test. If the matched element is immediately preceeded by a NewLine command, then we insert another NewLine before the matched command, then return this new NewLine instead (thus the about to be inserted command will be placed between the two NewLines)
     3507                Node sibling_element = matched_element.getPreviousSibling ();
     3508                if(sibling_element != null && sibling_element.getNodeName ().equals (NEWLINE_ELEMENT)) {
     3509                    Element newline_element = document.createElement (NEWLINE_ELEMENT);
     3510                    document_element.insertBefore (newline_element, sibling_element);
     3511                }
     3512                return sibling_element; // Note that this may be null
     3513            }
     3514            susceeding_index++;
     3515        }
     3516        // Well. Apparently there are no other commands in this collection configuration. So append away...
     3517        return null;
     3518    }
     3519    // From collectionConfig.xml to internal structure:add 'ex.' namespace (if none).
     3520    // From internal structure to collectionConfig.xml:always peel off 'ex.' namespace (if any), except for format statement
     3521    //This method parses 'xml_file_doc' into 'dOc'
     3522    public void parseCollectionConfigXML (File xml_file, Document dOc) {
     3523       
     3524        Document xml_file_doc = XMLTools.parseXMLFile (xml_file);
     3525        Element fromElement = xml_file_doc.getDocumentElement ();
     3526        Element toElement = dOc.getDocumentElement ();
     3527       
     3528        // It's deliberately set that 'creator', 'maintainer', and 'public' are only in English (as they are just names).
     3529        // So the following ArrayList have only one element.
     3530        Node metadataListNode = XMLTools.getChildByTagNameIndexed (fromElement, StaticStrings.METADATALIST_STR, 0);
     3531        if (metadataListNode != null) {
     3532            ArrayList creator = doMetadataList (dOc, metadataListNode, StaticStrings.COLLECTIONMETADATA_CREATOR_ELEMENT,
     3533            StaticStrings.COLLECTIONMETADATA_CREATOR_STR);
     3534            ArrayList maintainer = doMetadataList (dOc, metadataListNode,
     3535            StaticStrings.COLLECTIONMETADATA_MAINTAINER_ELEMENT,
     3536            StaticStrings.COLLECTIONMETADATA_MAINTAINER_STR);
     3537            ArrayList is_public = doMetadataList (dOc, metadataListNode, StaticStrings.COLLECTIONMETADATA_PUBLIC_ELEMENT,
     3538            StaticStrings.COLLECTIONMETADATA_PUBLIC_STR);
     3539           
     3540            appendArrayList (toElement, creator);
     3541            appendArrayList (toElement, maintainer);
     3542            appendArrayList (toElement, is_public);
     3543        }
     3544       
     3545        Node searchNode = XMLTools.getChildByTagNameIndexed (fromElement, StaticStrings.SEARCH_STR, 0);
     3546        String buildtype_value = ((Element)searchNode).getAttribute (StaticStrings.TYPE_ATTRIBUTE);//might be mg|mgpp|lucene
     3547        Element buildtype = doBuildType (dOc, buildtype_value);
     3548        appendProperly (toElement, buildtype);
     3549       
     3550       
     3551        Node importNode = XMLTools.getChildByTagNameIndexed (fromElement, StaticStrings.IMPORT_STR, 0);
     3552        if (importNode == null) {
     3553            System.out.println ("There is no content in the 'import' block.");
     3554        }
     3555        if (importNode != null) {
     3556            Node pluginListNode = XMLTools.getChildByTagNameIndexed ((Element)importNode, StaticStrings.PLUGINLIST_STR, 0);
     3557           
     3558            if (pluginListNode == null) {
     3559                System.out.println ("There is no plugin set.");
     3560            }
     3561            if (pluginListNode != null) {
     3562               
     3563                doPlugin (dOc, pluginListNode);
     3564            }
     3565        }
     3566       
     3567        Node browseNode = XMLTools.getChildByTagNameIndexed (fromElement, StaticStrings.BROWSE_STR, 0);
     3568        if (browseNode != null) {
     3569            if (browseNode == null) {
     3570                System.out.println ("There is no classifier.");
     3571            }
     3572            doClassifier (dOc, browseNode);
     3573        }
     3574       
     3575        Node displayItemListNode = XMLTools.getChildByTagNameIndexed (fromElement, StaticStrings.DISPLAYITEMLIST_STR, 0);
     3576        if (displayItemListNode != null) {
     3577            ArrayList description = doDisplayItemList (dOc, displayItemListNode, StaticStrings.DESCRIPTION_STR,
     3578            StaticStrings.COLLECTIONMETADATA_COLLECTIONEXTRA_STR);
     3579            ArrayList smallicon = doDisplayItemList (dOc, displayItemListNode, StaticStrings.SMALLICON_STR,
     3580            StaticStrings.COLLECTIONMETADATA_ICONCOLLECTIONSMALL_STR);
     3581            ArrayList icon = doDisplayItemList (dOc, displayItemListNode, StaticStrings.ICON_STR,
     3582            StaticStrings.COLLECTIONMETADATA_ICONCOLLECTION_STR);
     3583            ArrayList name = doDisplayItemList (dOc, displayItemListNode, StaticStrings.NAME_STR,
     3584            StaticStrings.COLLECTIONMETADATA_COLLECTIONNAME_STR);
     3585           
     3586            appendArrayList (toElement, description);
     3587            appendArrayList (toElement, smallicon);
     3588            appendArrayList (toElement, icon);
     3589            appendArrayList (toElement, name);
     3590        }
     3591       
     3592        if (buildtype_value.equalsIgnoreCase ("mg")) {
     3593            doMGIndexes (dOc, searchNode);
     3594        }
     3595        else {
     3596            doMGPPIndexes (dOc, searchNode);
     3597        }
     3598       
     3599        doDefaultIndex (dOc, searchNode);
     3600        //doSearchType (dOc, searchNode);
     3601        doDefaultLevel (dOc, searchNode);
     3602        doLevel (dOc, searchNode);
     3603        doIndexOption (dOc, searchNode);
     3604        doSubcollection (dOc, searchNode);
     3605        doIndexSubcollection (dOc, searchNode);
     3606        doIndexLanguage (dOc, searchNode);
     3607        doDefaultIndexLanguage (dOc, searchNode);
     3608        doLanguageMetadata (dOc, searchNode);
     3609        doSearchFormat (dOc, searchNode);
     3610        doDisplayFormat (dOc, fromElement);
     3611        doReplaceListRef (dOc, fromElement);
     3612       
     3613    }
     3614   
     3615   
     3616    public void saveCollectionConfigXML (File collect_cfg_file, Document doc) {
     3617        //In this method, the file collect_cfg_file must be 'collectionConfig.xml' instead of 'collect.cfg'
     3618       
     3619       
     3620        //Compare the internal structure (doc) with the saved structure from collectionConfig.xml and see if it has changed
     3621        StringBuffer collect_cfg_string_buffer = new StringBuffer (XMLTools.xmlNodeToString (doc));
     3622        String collect_cfg_string = collect_cfg_string_buffer.toString ();
     3623        if (saved_collect_cfg_string_buffer != null) {
     3624            String saved_collect_cfg_string = saved_collect_cfg_string_buffer.toString ();
     3625            if (collect_cfg_string.equals (saved_collect_cfg_string)) {
     3626                DebugStream.println ("'collectionConfig.xml' file hasn't changed so no save necessary...");
     3627                return;
     3628            }
     3629        }
     3630       
     3631        DebugStream.println ("'collectionConfig.xml' file has changed, saving now...");
     3632       
     3633        // If we're using the Local Library we must release the collection before writing to the collect.cfg file
     3634        String collection_name = Gatherer.c_man.getCollection ().getName ();
     3635        boolean collection_released = false;
     3636        if (Gatherer.c_man.built () && LocalLibraryServer.isRunning () == true) {
     3637            // Release the collection
     3638            LocalLibraryServer.releaseCollection (collection_name);
     3639            collection_released = true;
     3640        }
     3641       
     3642        // Make a backup of the collectionConfig.xml file so that the user can manully change back
     3643        if (collect_cfg_file.exists ()) {
     3644           
     3645            File original_file = new File (collect_cfg_file.getParentFile (), Utility.COLLECTION_CONFIG_XML);
     3646            File backup_file = new File (collect_cfg_file.getParentFile (), Utility.COLLECTION_CONFIG_BAK);
     3647            if (backup_file.exists ()) {
     3648                backup_file.delete ();
     3649            }
     3650            if (!original_file.renameTo (backup_file)) {
     3651                System.err.println ("Warning: can't rename collectionConfig.xml to collectionConfig.bak.");
     3652            }
     3653        }
     3654       
     3655        Document collection_config_xml_document = convertInternalToCollectionConfig (doc);
     3656        String[] nonEscapingTagNames = {StaticStrings.FORMAT_STR};
     3657        XMLTools.writeXMLFile (collect_cfg_file, collection_config_xml_document, nonEscapingTagNames);
     3658        saved_collect_cfg_string_buffer = collect_cfg_string_buffer;
     3659       
     3660        // If we're using a remote Greenstone server, upload the new 'collectionConfig.xml' file
     3661        if (Gatherer.isGsdlRemote) {
     3662            RemoteGreenstoneServer.uploadCollectionFile (collection_name, collect_cfg_file);
     3663        }
     3664       
     3665        // Now re-add the collection to the Local Library server
     3666        if (collection_released) {
     3667            LocalLibraryServer.addCollection (collection_name);
     3668        }
     3669       
     3670    }
     3671    public void saveIfNecessary () {
     3672        if (Gatherer.GS3 == true) {
     3673            saveCollectionConfigXML (collect_cfg_file, document);
     3674            return;
     3675        }
     3676        // Convert the collection configuration XML tree to the collect.cfg version
     3677        StringBuffer collect_cfg_string_buffer = new StringBuffer ();
     3678        NodeList command_elements = document.getDocumentElement ().getChildNodes ();
     3679        boolean just_wrote_blank_line = false;  // Prevent two or more blank lines in a row
     3680        for (int i = 0; i < command_elements.getLength (); i++) {
     3681            Node command_node = command_elements.item (i);
     3682            if (!(command_node instanceof Element)) {
     3683                // We're only interested in Elements
     3684                continue;
     3685            }
     3686            Element command_element = (Element) command_node;
     3687           
     3688            // Handle NewLine elements (blank lines)
     3689            if (command_element.getNodeName ().equals (NEWLINE_ELEMENT) && !just_wrote_blank_line) {
     3690                collect_cfg_string_buffer.append ("\n");
     3691                just_wrote_blank_line = true;
     3692            }
     3693           
     3694            // Anything else we write to file, but only if it has been assigned, except for index and level commands
     3695            // (which just get commented out if unassigned -- a side effect of MG & MGPP compatibility)
     3696            else if (!command_element.getAttribute (StaticStrings.ASSIGNED_ATTRIBUTE).equals (StaticStrings.FALSE_STR) || command_element.getNodeName ().equals (StaticStrings.INDEXES_ELEMENT) || command_element.getNodeName ().equals (StaticStrings.INDEX_DEFAULT_ELEMENT) || command_element.getNodeName ().equals (StaticStrings.INDEXOPTIONS_ELEMENT) || command_element.getNodeName ().equals (StaticStrings.INDEXOPTION_DEFAULT_ELEMENT)) {
     3697                String command;
     3698                if (command_element.getNodeName ().equals (StaticStrings.FORMAT_ELEMENT)) {
     3699                    // Format statements we write out with ex. still present
     3700                    command = toString (command_element, true);
     3701                }
     3702                else {
     3703                    command = toString (command_element, false);
     3704                }
     3705               
     3706                if (command != null && command.length ()> 0 ) {
     3707                    collect_cfg_string_buffer.append (command + "\n");
     3708                    just_wrote_blank_line = false;
     3709                }
     3710            }
     3711        }
     3712       
     3713        String collect_cfg_string = collect_cfg_string_buffer.toString ();
     3714        String saved_collect_cfg_string = saved_collect_cfg_string_buffer.toString ();
     3715        if (collect_cfg_string.equals (saved_collect_cfg_string)) {
     3716            DebugStream.println ("Collect.cfg file hasn't changed so no save necessary...");
     3717            return;
     3718        }
     3719       
     3720        DebugStream.println ("Collect.cfg file has changed, saving now...");
     3721       
     3722        // If we're using the Local Library we must release the collection before writing to the collect.cfg file
     3723        String collection_name = CollectionManager.getLoadedCollectionName ();
     3724        boolean collection_released = false;
     3725        if (Gatherer.c_man.built () && LocalLibraryServer.isRunning () == true) {
     3726            // Release the collection
     3727            LocalLibraryServer.releaseCollection (collection_name);
     3728            collection_released = true;
     3729        }
     3730       
     3731        // Make a backup of the collect.cfg file
     3732        if (collect_cfg_file.exists ()) {
     3733            File original_file = new File (collect_cfg_file.getParentFile (), StaticStrings.COLLECT_CFG);
     3734            File backup_file = new File (collect_cfg_file.getParentFile (), Utility.COLLECT_BAK);
     3735            if (backup_file.exists ()) {
     3736                backup_file.delete ();
     3737            }
     3738            if (!original_file.renameTo (backup_file)) {
     3739                System.err.println ("Warning: can't rename collect.cfg to collect.bak.");
     3740            }
     3741        }
     3742       
     3743        try {
     3744            OutputStream ostream = new FileOutputStream (collect_cfg_file);
     3745            Writer file_writer = new OutputStreamWriter (ostream, ENCODING);
     3746            BufferedWriter buffered_writer = new BufferedWriter (file_writer);
     3747            buffered_writer.write (collect_cfg_string);
     3748            buffered_writer.close ();
     3749           
     3750            saved_collect_cfg_string_buffer = collect_cfg_string_buffer;
     3751           
     3752            // If we're using a remote Greenstone server, upload the new collect.cfg file
     3753            if (Gatherer.isGsdlRemote) {
     3754                RemoteGreenstoneServer.uploadCollectionFile (collection_name, collect_cfg_file);
     3755            }
     3756        }
     3757        catch (Exception exception) {
     3758            DebugStream.println ("Error in CollectionConfiguration.save(): " + exception);
     3759            DebugStream.printStackTrace (exception);
     3760        }
     3761       
     3762        // Now re-add the collection to the Local Library server
     3763        if (collection_released) {
     3764            LocalLibraryServer.addCollection (collection_name);
     3765        }
     3766    }
     3767    // This method is initilised in CollectionDesignManager.java constructor
     3768    public CollectionConfiguration (File collect_cfg_file) {
     3769        this.collect_cfg_file = collect_cfg_file;
     3770       
     3771        // parse the XML template
     3772        document = XMLTools.parseXMLFile ("xml/CollectionConfig.xml", true);
     3773        String filename = collect_cfg_file.getName ().toLowerCase ();
     3774       
     3775        if (filename.endsWith (".cfg")) {
     3776            parse (collect_cfg_file);
     3777        }
     3778        if (filename.endsWith (".xml")) {
     3779            parseCollectionConfigXML (collect_cfg_file, document);
     3780        }
     3781       
     3782        //XMLTools.printXMLNode(document.getDocumentElement());
     3783    }
     3784   
     3785    // Append the elements, which are of Element type, in 'list' to Element 'to'
     3786    private void appendArrayList (Element to, ArrayList list) {
     3787        if (list == null) return;
     3788       
     3789        for (int i=0; i<list.size (); i++) {
     3790            appendProperly (to, (Element)list.get (i));
     3791        }
     3792    }
     3793    //Convert the internal XML DOM tree (dOc) into that of collectionConfig.xml (skeleton)
     3794    public Document convertInternalToCollectionConfig (Document dOc) {
     3795        //first parse an empty skeleton of xml config file
     3796        //The aim is to convert the internal structure into this skeleton
     3797        Document skeleton = XMLTools.parseXMLFile ("xml/CollectionConfig.xml", true);
     3798        //Element internal = dOc.getDocumentElement();
     3799        convertMetadataList (dOc, skeleton);
     3800        convertDisplayItemList (dOc, skeleton);
     3801        convertBuildType (dOc, skeleton);
     3802        convertIndex (dOc, skeleton);
     3803        convertPlugin (dOc, skeleton);
     3804        convertClassifier (dOc, skeleton);
     3805        convertSubcollectionIndexes (dOc, skeleton);
     3806        convertLanguages (dOc, skeleton);
     3807        convertSubcollection (dOc, skeleton);
     3808        convertSearchType (dOc, skeleton);
     3809        convertSearchFormat (dOc, skeleton);
     3810        convertDisplayFormat (dOc, skeleton);
     3811        convertReplaceListRef (dOc, skeleton);
     3812       
     3813        return skeleton;
     3814    }
     3815    ///*********************************************************************************************************///
    17843816}
Note: See TracChangeset for help on using the changeset viewer.