source: main/trunk/gli/src/org/greenstone/gatherer/cdm/CollectionConfiguration.java@ 24824

Last change on this file since 24824 was 24824, checked in by sjm84, 12 years ago

Reformatting this file ahead of some changes

  • Property svn:keywords set to Author Date Id Revision
File size: 21.9 KB
Line 
1/**
2 *#########################################################################
3 *
4 * A component of the Gatherer application, part of the Greenstone digital
5 * library suite from the New Zealand Digital Library Project at the
6 * University of Waikato, New Zealand.
7 *
8 * Author: John Thompson, Greenstone Digital Library, University of Waikato
9 *
10 * Copyright (C) 1999 New Zealand Digital Library Project
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 *########################################################################
26 */
27package org.greenstone.gatherer.cdm;
28
29import java.awt.*;
30import java.awt.event.*;
31import java.io.*;
32import java.util.*;
33import javax.swing.*;
34import org.greenstone.gatherer.DebugStream;
35import org.greenstone.gatherer.Gatherer;
36import org.greenstone.gatherer.collection.CollectionManager;
37import org.greenstone.gatherer.greenstone.LocalLibraryServer;
38import org.greenstone.gatherer.gui.GLIButton;
39import org.greenstone.gatherer.remote.RemoteGreenstoneServer;
40import org.greenstone.gatherer.util.DOMTree;
41import org.greenstone.gatherer.util.StaticStrings;
42import org.greenstone.gatherer.util.XMLTools;
43import org.greenstone.gatherer.util.Utility;
44import org.w3c.dom.*;
45
46/**
47 * This class provides access to an xml-type view of the collect.cfg file. This
48 * is useful as it allows the manipulation and free form editing of a
49 * collect.cfg file while still allowing the various CDM data managers to base
50 * themselves directly on this model (whereas they used to be independant
51 * ListModels which clobbered the ordering of unparsed commands).
52 *
53 * @author John Thompson, Greenstone Digital Library, University of Waikato
54 */
55public class CollectionConfiguration
56{
57 static final public String ENCODING = "UTF-8";
58 static final public String NEWLINE_ELEMENT = "NewLine";
59
60 static private Document document;
61 static private String saved_config_file_string = null;
62
63 // may be collec.cfg (GS2) or collectionConfig.xml (GS3)
64 private File collect_config_file;
65 private String collect_config_filename;
66
67 // This method is initilised in CollectionDesignManager.java constructor
68 public CollectionConfiguration(File collect_config_file)
69 {
70 this.collect_config_file = collect_config_file;
71 this.collect_config_filename = collect_config_file.getName();
72 // parse the XML template
73 document = XMLTools.parseXMLFile("xml/CollectionConfig.xml", true);
74 String filename = collect_config_filename.toLowerCase();
75
76 if (filename.endsWith(".cfg"))
77 {
78 saved_config_file_string = CollectCfgReadWrite.parse(collect_config_file, document);
79 }
80 else if (filename.endsWith(".xml"))
81 {
82 CollectionConfigXMLReadWrite.parse(collect_config_file, document);
83 }
84
85 //XMLTools.printXMLNode(document.getDocumentElement());
86 }
87
88 static public Element createElement(String element_name)
89 {
90 return document.createElement(element_name);
91 }
92
93 /** Gives the preferred ordering of commands */
94 static final public 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 };
95
96 /**
97 * Find the best insertion position for the given DOM Element. This should
98 * try to match command tag, and if found should then try to group by name
99 * or type (eg CollectionMeta), or append to end is no such grouping exists
100 * (eg Plugins). Failing a command match it will check against the command
101 * order for the best insertion location.
102 *
103 * @param target_element
104 * the command Element to be inserted
105 * @return the Element which the given command should be inserted before, or
106 * null to append to end of list
107 */
108 static public Node findInsertionPoint(Element target_element)
109 {
110 ///ystem.err.println("Find insertion point: " + target_element.getNodeName());
111 String target_element_name = target_element.getNodeName();
112 Element document_element = document.getDocumentElement();
113 // Try to find commands with the same tag.
114 NodeList matching_elements = document_element.getElementsByTagName(target_element_name);
115 // If we found matching elements, then we have our most likely insertion location, so check within for groupings
116 if (matching_elements.getLength() != 0)
117 {
118 ///ystem.err.println("Found matching elements.");
119 // Only CollectionMeta are grouped.
120 if (target_element_name.equals(StaticStrings.COLLECTIONMETADATA_ELEMENT))
121 {
122 ///ystem.err.println("Dealing with collection metadata");
123 // 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.
124 // So if the command to be added is special add it immediately after any other special command
125 if (target_element.getAttribute(StaticStrings.SPECIAL_ATTRIBUTE).equals(StaticStrings.TRUE_STR))
126 {
127 int index = 0;
128 Element matched_element = (Element) matching_elements.item(index);
129 Element sibling_element = (Element) matched_element.getNextSibling();
130 while (sibling_element.getAttribute(StaticStrings.SPECIAL_ATTRIBUTE).equals(StaticStrings.TRUE_STR))
131 {
132 index++;
133 matched_element = (Element) matching_elements.item(index);
134 sibling_element = (Element) matched_element.getNextSibling();
135 }
136 if (sibling_element.getNodeName().equals(NEWLINE_ELEMENT))
137 {
138 Element newline_element = document.createElement(NEWLINE_ELEMENT);
139 document_element.insertBefore(newline_element, sibling_element);
140 }
141 return sibling_element;
142 }
143 // Otherwise try to find a matching 'name' and add after the last one in that group.
144 else
145 {
146 int index = 0;
147 target_element_name = target_element.getAttribute(StaticStrings.NAME_ATTRIBUTE);
148 boolean found = false;
149 // Skip all of the special metadata
150 Element matched_element = (Element) matching_elements.item(index);
151 while (matched_element.getAttribute(StaticStrings.SPECIAL_ATTRIBUTE).equals(StaticStrings.TRUE_STR))
152 {
153 index++;
154 matched_element = (Element) matching_elements.item(index);
155 }
156 // Begin search
157 while (!found && matched_element != null)
158 {
159 if (matched_element.getAttribute(StaticStrings.NAME_ATTRIBUTE).equals(target_element_name))
160 {
161 found = true;
162 }
163 else
164 {
165 index++;
166 matched_element = (Element) matching_elements.item(index);
167 }
168 }
169 // If we found a match, we need to continue checking until we find the last name match.
170 if (found)
171 {
172 index++;
173 Element previous_sibling = matched_element;
174 Element sibling_element = (Element) matching_elements.item(index);
175 while (sibling_element != null && sibling_element.getAttribute(StaticStrings.NAME_ATTRIBUTE).equals(target_element_name))
176 {
177 previous_sibling = sibling_element;
178 index++;
179 sibling_element = (Element) matching_elements.item(index);
180 }
181 // 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!
182 return previous_sibling.getNextSibling();
183 }
184 // If not found we just add after last metadata element
185 else
186 {
187 Element last_element = (Element) matching_elements.item(matching_elements.getLength() - 1);
188 return last_element.getNextSibling();
189 }
190 }
191
192 }
193 else
194 {
195 ///ystem.err.println("Not dealing with collection meta.");
196 Element matched_element = (Element) matching_elements.item(matching_elements.getLength() - 1);
197 // 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)
198 Node sibling_element = matched_element.getNextSibling();
199 if (sibling_element != null && sibling_element.getNodeName().equals(NEWLINE_ELEMENT))
200 {
201 Element newline_element = document.createElement(NEWLINE_ELEMENT);
202 document_element.insertBefore(newline_element, sibling_element);
203 }
204 return sibling_element; // Note that this may be null
205 }
206 }
207 ///ystem.err.println("No matching elements found.");
208 // Locate where this command is in the ordering
209 int command_index = -1;
210 for (int i = 0; command_index == -1 && i < COMMAND_ORDER.length; i++)
211 {
212 if (COMMAND_ORDER[i].equals(target_element_name))
213 {
214 command_index = i;
215 }
216 }
217 ///ystem.err.println("Command index is: " + command_index);
218 // Now move forward, checking for existing elements in each of the preceeding command orders.
219 int preceeding_index = command_index - 1;
220 ///ystem.err.println("Searching before the target command.");
221 while (preceeding_index >= 0)
222 {
223 matching_elements = document_element.getElementsByTagName(COMMAND_ORDER[preceeding_index]);
224 // If we've found a match
225 if (matching_elements.getLength() > 0)
226 {
227 // We add after the last element
228 Element matched_element = (Element) matching_elements.item(matching_elements.getLength() - 1);
229 // 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)
230 Node sibling_element = matched_element.getNextSibling();
231 if (sibling_element != null && sibling_element.getNodeName().equals(NEWLINE_ELEMENT))
232 {
233 Element newline_element = document.createElement(NEWLINE_ELEMENT);
234 document_element.insertBefore(newline_element, sibling_element);
235 }
236 return sibling_element; // Note that this may be null
237 }
238 preceeding_index--;
239 }
240 // If all that fails, we now move backwards through the commands
241 int susceeding_index = command_index + 1;
242 ///ystem.err.println("Searching after the target command.");
243 while (susceeding_index < COMMAND_ORDER.length)
244 {
245 matching_elements = document_element.getElementsByTagName(COMMAND_ORDER[susceeding_index]);
246 // If we've found a match
247 if (matching_elements.getLength() > 0)
248 {
249 // We add before the first element
250 Element matched_element = (Element) matching_elements.item(0);
251 // 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)
252 Node sibling_element = matched_element.getPreviousSibling();
253 if (sibling_element != null && sibling_element.getNodeName().equals(NEWLINE_ELEMENT))
254 {
255 Element newline_element = document.createElement(NEWLINE_ELEMENT);
256 document_element.insertBefore(newline_element, sibling_element);
257 }
258 return sibling_element; // Note that this may be null
259 }
260 susceeding_index++;
261 }
262 // Well. Apparently there are no other commands in this collection configuration. So append away...
263 return null;
264 }
265
266 static public NodeList getElementsByTagName(String element_name)
267 {
268 return document.getDocumentElement().getElementsByTagName(element_name);
269 }
270
271 public Element getDocumentElement()
272 {
273 return document.getDocumentElement();
274 }
275
276 /**
277 * This debug facility shows the currently loaded collect.cfg or
278 * CollectConfig.xml file as a DOM tree.
279 */
280 public void display()
281 {
282 JDialog dialog = new JDialog(Gatherer.g_man, "Collection Configuration", false);
283 dialog.setSize(400, 400);
284 JPanel content_pane = (JPanel) dialog.getContentPane();
285 final DOMTree tree = new DOMTree(document);
286 JButton refresh_button = new GLIButton("Refresh Tree");
287 refresh_button.addActionListener(new ActionListener()
288 {
289 public void actionPerformed(ActionEvent event)
290 {
291 tree.setDocument(document);
292 }
293 });
294 content_pane.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
295 content_pane.setLayout(new BorderLayout());
296 content_pane.add(new JScrollPane(tree), BorderLayout.CENTER);
297 content_pane.add(refresh_button, BorderLayout.SOUTH);
298 dialog.setVisible(true);
299 }
300
301 public File getFile()
302 {
303 return collect_config_file;
304 }
305
306 public Element getCreator()
307 {
308 Element element = getOrCreateElementByTagName(StaticStrings.COLLECTIONMETADATA_CREATOR_ELEMENT, null, null);
309 element.setAttribute(StaticStrings.NAME_ATTRIBUTE, StaticStrings.COLLECTIONMETADATA_CREATOR_STR);
310 element.setAttribute(StaticStrings.SPECIAL_ATTRIBUTE, StaticStrings.TRUE_STR);
311 return element;
312 }
313
314 public Element getMaintainer()
315 {
316 Element element = getOrCreateElementByTagName(StaticStrings.COLLECTIONMETADATA_MAINTAINER_ELEMENT, null, null);
317 element.setAttribute(StaticStrings.NAME_ATTRIBUTE, StaticStrings.COLLECTIONMETADATA_MAINTAINER_STR);
318 element.setAttribute(StaticStrings.SPECIAL_ATTRIBUTE, StaticStrings.TRUE_STR);
319 return element;
320 }
321
322 /** Retrieve or create the languages Element. */
323 public Element getLanguages()
324 {
325 return getOrCreateElementByTagName(StaticStrings.LANGUAGES_ELEMENT, null, null);
326 }
327
328 public Element getLanguageMetadata()
329 {
330 return getOrCreateElementByTagName(StaticStrings.LANGUAGE_METADATA_ELEMENT, null, null);
331 }
332
333 public Element getLevels()
334 {
335 return getOrCreateElementByTagName(StaticStrings.INDEXOPTIONS_ELEMENT, StaticStrings.NAME_ATTRIBUTE, StaticStrings.LEVELS_STR);
336 }
337
338 public Element getLevelDefault()
339 {
340 return getOrCreateElementByTagName(StaticStrings.INDEXOPTION_DEFAULT_ELEMENT, StaticStrings.NAME_ATTRIBUTE, StaticStrings.LEVEL_DEFAULT_STR);
341 }
342
343 public Element getIndexOptions()
344 {
345 return getOrCreateElementByTagName(StaticStrings.INDEXOPTIONS_ELEMENT, StaticStrings.NAME_ATTRIBUTE, StaticStrings.INDEXOPTIONS_STR);
346 }
347
348 /**
349 * Retrieve or create the indexes Element. Note that this method behaves
350 * differently from the other getBlah methods, in that it also has to keep
351 * in mind that indexes come in two flavours, MG and MGPP.
352 */
353 public Element getMGIndexes()
354 {
355 return getOrCreateElementByTagName(StaticStrings.INDEXES_ELEMENT, StaticStrings.MGPP_ATTRIBUTE, StaticStrings.FALSE_STR);
356 }
357
358 public Element getMGPPIndexes()
359 {
360 return getOrCreateElementByTagName(StaticStrings.INDEXES_ELEMENT, StaticStrings.MGPP_ATTRIBUTE, StaticStrings.TRUE_STR);
361 }
362
363 public Element getPublic()
364 {
365 Element element = getOrCreateElementByTagName(StaticStrings.COLLECTIONMETADATA_PUBLIC_ELEMENT, null, null);
366 element.setAttribute(StaticStrings.NAME_ATTRIBUTE, StaticStrings.COLLECTIONMETADATA_PUBLIC_STR);
367 element.setAttribute(StaticStrings.SPECIAL_ATTRIBUTE, StaticStrings.TRUE_STR);
368 return element;
369 }
370
371 public Element getBuildType()
372 {
373 Element element = getOrCreateElementByTagName(StaticStrings.BUILDTYPE_ELEMENT, null, null);
374 element.setAttribute(StaticStrings.NAME_ATTRIBUTE, StaticStrings.BUILDTYPE_STR);
375 element.setAttribute(StaticStrings.SPECIAL_ATTRIBUTE, StaticStrings.TRUE_STR);
376 return element;
377
378 }
379
380 public Element getDatabaseType()
381 {
382 Element element = getOrCreateElementByTagName(StaticStrings.DATABASETYPE_ELEMENT, null, null);
383 element.setAttribute(StaticStrings.NAME_ATTRIBUTE, StaticStrings.DATABASETYPE_STR);
384 element.setAttribute(StaticStrings.SPECIAL_ATTRIBUTE, StaticStrings.TRUE_STR);
385 return element;
386
387 }
388
389 /** Retrieve or create the subindexes Element. */
390 public Element getSubIndexes()
391 {
392 return getOrCreateElementByTagName(StaticStrings.SUBCOLLECTION_INDEXES_ELEMENT, null, null);
393 }
394
395 /** Retrieve or create the supercollections Element. */
396 public Element getSuperCollection()
397 {
398 return getOrCreateElementByTagName(StaticStrings.SUPERCOLLECTION_ELEMENT, null, null);
399 }
400
401 public boolean ready()
402 {
403 return document != null;
404 }
405
406 /** ************************** Private Methods ***************************/
407
408 /** Retrieve or create the indexes Element. */
409 static private Element getOrCreateElementByTagName(String name, String conditional_attribute, String required_value)
410 {
411 Element document_element = document.getDocumentElement();
412 NodeList elements = document_element.getElementsByTagName(name);
413 int elements_length = elements.getLength();
414 if (elements_length > 0)
415 {
416 if (conditional_attribute == null)
417 {
418 document_element = null;
419 return (Element) elements.item(0);
420 }
421 else
422 {
423 for (int i = 0; i < elements_length; i++)
424 {
425 Element element = (Element) elements.item(i);
426 if (element.getAttribute(conditional_attribute).equals(required_value))
427 {
428 document_element = null;
429 return element;
430 }
431 element = null;
432 }
433 }
434 }
435 // Create the element
436 Element element = document.createElement(name);
437 // If there was a property set it
438 if (conditional_attribute != null)
439 {
440 element.setAttribute(conditional_attribute, required_value);
441 }
442 Node target_node = findInsertionPoint(element);
443 if (target_node != null)
444 {
445 document_element.insertBefore(element, target_node);
446 }
447 else
448 {
449 document_element.appendChild(element);
450 }
451 document_element = null;
452 return element;
453 }
454
455 /**
456 * Write the text to the buffer. This is used so we don't have to worry
457 * about storing intermediate String values just so we can calaulate length
458 * and offset.
459 *
460 * @param writer
461 * the BufferedWriter to which the str will be written
462 * @param str
463 * the String to be written
464 */
465 private void write(BufferedWriter writer, String str) throws IOException
466 {
467 writer.write(str, 0, str.length());
468 }
469
470 public void saveIfNecessary()
471 {
472
473 // Generate a string version of internal document
474 String config_file_string = null;
475 if (Gatherer.GS3)
476 {
477 config_file_string = CollectionConfigXMLReadWrite.generateStringVersion(document);
478 }
479 else
480 {
481 config_file_string = CollectCfgReadWrite.generateStringVersion(document);
482 }
483 // compare to saved version
484 if (saved_config_file_string != null)
485 {
486 if (saved_config_file_string.equals(config_file_string))
487 {
488 DebugStream.println(collect_config_filename + " file hasn't changed so no save necessary...");
489 return;
490 }
491 }
492
493 // We need to save...
494 DebugStream.println(collect_config_filename + " file has changed, saving now...");
495
496 // If we're using the Local Library we must release the collection before writing to the collect.cfg file
497 String collection_name = CollectionManager.getLoadedCollectionName(true); // url style slash
498 boolean collection_released = false;
499 if (Gatherer.c_man.built() && LocalLibraryServer.isRunning() == true)
500 {
501 // Release the collection
502 LocalLibraryServer.releaseCollection(collection_name);
503 collection_released = true;
504 }
505
506 // Make a backup of the existing config file
507 if (collect_config_file.exists())
508 {
509 String config_filename;
510 String backup_filename;
511 if (Gatherer.GS3)
512 {
513 config_filename = Utility.COLLECTION_CONFIG_XML;
514 backup_filename = Utility.COLLECTION_CONFIG_BAK;
515 }
516 else
517 {
518 config_filename = StaticStrings.COLLECT_CFG;
519 backup_filename = Utility.COLLECT_BAK;
520 }
521 File original_file = new File(collect_config_file.getParentFile(), config_filename);
522 File backup_file = new File(collect_config_file.getParentFile(), backup_filename);
523 if (backup_file.exists())
524 {
525 backup_file.delete();
526 }
527 if (!original_file.renameTo(backup_file))
528 {
529 System.err.println("Warning: can't rename " + config_filename + " to " + backup_filename);
530 }
531 }
532
533 // now save the file
534 if (Gatherer.GS3)
535 {
536 CollectionConfigXMLReadWrite.save(collect_config_file, document);
537 }
538 else
539 {
540 // we have already converted to string, so save here
541 try
542 {
543 OutputStream ostream = new FileOutputStream(collect_config_file);
544 Writer file_writer = new OutputStreamWriter(ostream, ENCODING);
545 BufferedWriter buffered_writer = new BufferedWriter(file_writer);
546 buffered_writer.write(config_file_string);
547 buffered_writer.close();
548 }
549 catch (Exception exception)
550 {
551 DebugStream.println("Error in CollectionConfiguration.save(): " + exception);
552 DebugStream.printStackTrace(exception);
553 }
554
555 }
556
557 // save the string version
558 saved_config_file_string = config_file_string;
559
560 // If we're using a remote Greenstone server, upload the new collect.cfg file
561 if (Gatherer.isGsdlRemote)
562 {
563 Gatherer.remoteGreenstoneServer.uploadCollectionFile(collection_name, collect_config_file);
564 }
565
566 // Now re-add the collection to the Local Library server
567 if (collection_released)
568 {
569 LocalLibraryServer.addCollection(collection_name);
570 }
571 }
572
573}
Note: See TracBrowser for help on using the repository browser.