source: trunk/gli/src/org/greenstone/gatherer/msm/MetadataSet.java@ 8236

Last change on this file since 8236 was 8236, checked in by mdewsnip, 20 years ago

Replaced all Gatherer.print* with DebugStream.print*.

  • Property svn:keywords set to Author Date Id Revision
File size: 25.8 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 * <BR><BR>
9 *
10 * Author: John Thompson, Greenstone Digital Library, University of Waikato
11 *
12 * <BR><BR>
13 *
14 * Copyright (C) 1999 New Zealand Digital Library Project
15 *
16 * <BR><BR>
17 *
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or
21 * (at your option) any later version.
22 *
23 * <BR><BR>
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * <BR><BR>
31 *
32 * You should have received a copy of the GNU General Public License
33 * along with this program; if not, write to the Free Software
34 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
35 *########################################################################
36 */
37package org.greenstone.gatherer.msm;
38
39import java.io.*;
40import java.net.*;
41import java.util.*;
42import org.apache.xerces.dom.*;
43import org.greenstone.gatherer.Configuration;
44import org.greenstone.gatherer.DebugStream;
45import org.greenstone.gatherer.Dictionary;
46import org.greenstone.gatherer.Gatherer;
47import org.greenstone.gatherer.valuetree.GValueModel;
48import org.greenstone.gatherer.valuetree.GValueNode;
49import org.greenstone.gatherer.util.StaticStrings;
50import org.greenstone.gatherer.util.Utility;
51import org.w3c.dom.*;
52/** An semi-data class to hold details about a loaded metadata set, it also provides some methods to manipulating the data within.
53 * @author John Thompson, Greenstone Digital Library, University of Waikato
54 * @version 2.3b
55 */
56public class MetadataSet {
57 /** The <Strong>Document</strong> of the DOM model. */
58 private Document document = null;
59 /** The document <strong>Element</strong> of the DOM model. */
60 private Element root = null;
61 /** The <strong>File</strong> this metadata set was loaded from. */
62 private File file = null;
63 /** A mapping from metadata elements to the root element of the value trees for that element. */
64 private Hashtable value_trees = null;
65 /** The list of metadata elements which are, of course, children of the root node. */
66 private NodeList elements = null;
67
68 private String current_language_code;
69 /** The description of this metadata set. Cached as it takes more computation time. */
70 private String description = null;
71 /** The name of this metadata set. Cached as it takes more computation time. */
72 private String name = null;
73 /** An element of the tree pruning filter enumeration, that indicates all nodes in the tree should be retained. */
74 static final int ALL_VALUES = 1;
75 /** An element of the tree pruning filter enumeration, that indicates only metadata Subject nodes or higher should remain after pruning. */
76 static final int SUBJECTS_ONLY = 2;
77 /** An element of the tree pruning filter enumeration, that indicates no value nodes i.e. the entire AssignedValues subtree, should remain after pruning. */
78 static final int NO_VALUES = 3;
79
80 public MetadataSet(String metadata_template) {
81
82 this.file = new File(metadata_template);
83 this.value_trees = new Hashtable();
84 this.document = Utility.parse(metadata_template, true);
85
86 init(true); // use class loader
87 }
88
89 /** Constructor.
90 * @param file The file the metadata set should be loaded from.
91 */
92 public MetadataSet(File file) {
93 this.file = file;
94 this.value_trees = new Hashtable();
95 this.document = Utility.parse(file, false);
96
97 init(false); // don't use class loader
98 }
99
100 /** Copy constructor.
101 * @param original The original metadata set to copy from.
102 */
103 public MetadataSet(MetadataSet original) {
104 this.value_trees = new Hashtable();
105 // We have to create a new document.
106 document = new DocumentImpl(original.getDocument().getDoctype());
107 root = (Element) document.importNode(original.getDocument().getDocumentElement(), true);
108 document.appendChild(root);
109 elements = root.getElementsByTagName("Element");
110 file = original.getFile();
111 // Now for each element read in its value tree if present.
112 for(int i = elements.getLength() - 1; i >= 0; i--) {
113 ElementWrapper value_element_wrapper = new ElementWrapper((Element)elements.item(i));
114 GValueModel value_tree = original.getValueTree(value_element_wrapper);
115 Document value_document = value_tree.getDocument();
116 Document value_document_copy = new DocumentImpl(value_document.getDoctype());
117 Element value_element = value_document.getDocumentElement();
118 Element value_element_copy = (Element) value_document_copy.importNode(value_element, true);
119 value_document_copy.appendChild(value_element_copy);
120 GValueModel value_tree_copy = new GValueModel(value_element_wrapper, value_document_copy);
121 value_trees.put(value_element_wrapper, value_tree_copy);
122 }
123 }
124 /** Conditional copy constructor.
125 * @param original The original metadata set to copy from.
126 * @param condition An <i>int</i> which matches one of the tree pruning filter types.
127 */
128 public MetadataSet(MetadataSet original, int condition) {
129 this(original);
130 // Now based on condition, we may have to remove some nodes from
131 // this model.
132 switch(condition) {
133 case ALL_VALUES:
134 // Do nothing.
135 break;
136 case SUBJECTS_ONLY:
137 // For each element retrieve its AssignedValues element.
138 for(Enumeration keys = value_trees.keys(); keys.hasMoreElements(); ) {
139 ElementWrapper value_element = (ElementWrapper)keys.nextElement();
140 GValueModel value_tree = (GValueModel)value_trees.get(value_element);
141 Document value_tree_document = value_tree.getDocument();
142 Element value_tree_root_element = value_tree_document.getDocumentElement();
143 // Traverse tree and remove leaf nodes.
144 MSMUtils.traverseTree(value_tree_root_element, MSMUtils.NONE, true);
145 }
146 break;
147 case NO_VALUES:
148 // Remove assigned values trees.
149 value_trees.clear();
150 break;
151 }
152 }
153
154 /** Add a mds level attribute.
155 * @param name The name of the attribute to add as a <Strong>String</strong>.
156 * @param value The value as a <strong>String</strong>.
157 */
158 public void addAttribute(String name, String value) {
159 root.setAttribute(name, value);
160 }
161
162 /** Add a new default metadata element with the given name to this metadata set.
163 * @param name The name of this element as a <strong>String</strong>.
164 * @return An <strong>ElementWrapper</strong> around the newly created element or null if the element was not created.
165 */
166 public ElementWrapper addElement(String name, String language)
167 {
168 Text text = document.createTextNode(name);
169 Element identifier = document.createElementNS("","Attribute");
170 identifier.setAttribute("name","identifier");
171 identifier.setAttribute("language", language);
172 identifier.appendChild(text);
173 Element element = document.createElementNS("","Element");
174 element.setAttribute("name",name);
175 element.appendChild(identifier);
176 root.appendChild(element);
177 return new ElementWrapper(element);
178 }
179
180 /** Method to add a new metadata element to this metadata set, if and only if the element is not already present.
181 * @param others_element An <strong>Element</strong> we wish to add to this metadata set, that currently belongs to some other set.
182 * @param model A <strong>GValueModel</strong> value tree
183 * @return <i>null</i> if the add is successful, otherwise a <strong>String</strong> containing an error message (phrase key).
184 */
185 public String addElement(Element others_element, GValueModel model) {
186 if(!containsElement(others_element.getAttribute("name"))) {
187 // First get ownership of the new element, then add it.
188 Element our_element = (Element)document.importNode(others_element, true);
189 // add the value tree
190 root.appendChild(our_element);
191 if (model != null) {
192 addValueTree(new ElementWrapper(our_element), model);
193 }
194 return null;
195 }
196 else {
197 return "MSMPrompt.Name_Exists";
198 }
199 }
200
201 /** Method to add a new metadata element with the specified new name to this metadata set, if and only if the name is not already in use.
202 * @param others_element An <strong>Element</strong> we wish to add to this metadata set, that currently belongs to some other set.
203 * @param new_name The new name to be given this element, as a <strong>String</strong>.
204 * @param model A <strong>GValueModel</strong> value tree
205 * @return <i>null</i> if the add is successful, otherwise a <strong>String</strong> containing an error message (phrase key).
206 */
207 public String addElement(Element others_element, String new_name, GValueModel model) {
208 if(!containsElement(new_name)) {
209 // First get ownership of the new element, then add it.
210 Element our_element =
211 (Element) document.importNode(others_element, true);
212 // Change name
213 our_element.setAttribute("name", new_name);
214 // we also want to change the english identifier of this element
215 MSMUtils.setIdentifier(our_element, new_name);
216 // Add it to teh set
217 root.appendChild(our_element);
218 // add the value tree
219 if (model != null) {
220 addValueTree(new ElementWrapper(our_element), model);
221 }
222 return null;
223 }
224 else {
225 return "MSMPrompt.Name_Exists";
226 }
227 }
228 /** Add a value tree to a given metadata element.
229 * @param element The <strong>ElementWrapper</strong> containing the element you wish to add a value tree for.
230 * @param model A <strong>GValueModel</strong> value tree
231 */
232 public void addValueTree(ElementWrapper element, GValueModel model) {
233 ///ystem.err.println("Adding value tree for " + element.toString());
234 value_trees.put(element, model);
235 }
236
237 public int compare(Element e1, Element e2) {
238 int result = 0;
239 // Check that they're not the same element.
240 if(e1 != e2) {
241 int index_e1 = -1;
242 int index_e2 = -1;
243 // Locate the indexes for each element.
244 for(int i = 0; i < elements.getLength(); i++) {
245 Node element = elements.item(i);
246 if(element == e1) {
247 index_e1 = i;
248 }
249 if(element == e2) {
250 index_e2 = i;
251 }
252 }
253 if(index_e1 < index_e2) {
254 result = -1;
255 }
256 else {
257 result = 1;
258 }
259 }
260 return result;
261 }
262
263 /** A method to determine if this metadata set contains an element with a certain name (case sensitive).
264 * @param name A <strong>String</strong> which is the name of the element whose presence we are checking.
265 * @return A <i>boolean</i> which is <i>true</i> if the named element exists, <i>false</i> otherwise.
266 */
267 public boolean containsElement(String name) {
268 for(int i = 0; i < elements.getLength(); i++) {
269 Element sibling = (Element) elements.item(i);
270 String sibling_name = sibling.getAttribute("name");
271 if(sibling_name.equals(name)) {
272 return true;
273 }
274 }
275 return false;
276 }
277
278 public NamedNodeMap getAttributes() {
279 return root.getAttributes();
280 }
281
282 /** Method to retrieve the contact address of the metadata set creator.
283 * @return A <strong>String</strong> containing the address.
284 */
285 /* private String getContact() {
286 return root.getAttribute("contact");
287 } */
288 /** Method to retrieve the name of the creator of this metadata set.
289 * @return A <strong>String</strong> containing the name.
290 */
291 public String getCreator() {
292 return root.getAttribute("creator");
293 }
294 /** Method to retrieve the description of this metadata set. Note that this is language specific, so we determine the desired language from the Dictionary. If no such entry exists, first try returning the english version and failing that the first description found.
295 * @return The description as a <strong>String</strong>.
296 */
297 public String getDescription() {
298 if(current_language_code != null && !Configuration.getLanguage().equals(current_language_code)) {
299 description = null;
300 }
301 if(description == null) {
302 description = getAttribute(StaticStrings.DESCRIPTION_ELEMENT, Dictionary.get("MSM.No_Description"));
303 }
304 return description;
305 }
306
307 /** Method to retrieve the <strong>Document</strong> associated with this metadata set.
308 * @return The <strong>Document</strong> representing this metadata set.
309 */
310 public Document getDocument() {
311 return document;
312 }
313 /** Method to retrieve the metadata element indicated by an index.
314 * @param index An <i>int</i> specifying the required element.
315 * @return The <strong>Element</strong> at the index.
316 */
317 public Element getElement(int index) {
318 return (Element)elements.item(index);
319 }
320 /** This method is used to acquire a reference to the element which matches the given metadata. Note that this is not the same as <i>metadata.getElement()</i> as the reference returned by it may now be obsolete.
321 * @param metadata A <strong>Metadata</strong> object representing an element and value assignment.
322 * @return A 'live' reference to an <strong>Element</strong> which is the same as that referenced by the given metadata, or <i>null</i> if there is no such element.
323 */
324 public Element getElement(Metadata metadata) {
325 return metadata.getElement().getElement();
326 }
327 /** This method is used to acquire a reference to the element which has the name specified. Note that this is not the same as <i>metadata.getElement()</i> as the reference returned by it may now be obsolete.
328 * @param name A <strong>String</strong> stating the desired objects name.
329 * @return A 'live' reference to an <strong>Element</strong> which is the same as that referenced by the given metadata, or <i>null</i> if there is no such element.
330 */
331 public Element getElement(String name) {
332 // Strip any namespace.
333 while(name.indexOf(".") != -1 && !name.equals(".")) {
334 name = name.substring(name.indexOf(".") + 1);
335 }
336 ///ystem.err.println("Get element named " + name);
337 for(int i = 0; i < elements.getLength(); i++) {
338 Element element = (Element) elements.item(i);
339 ///ystem.err.println("Compare to: " + element.getAttribute("name"));
340 if(element.getAttribute("name").equals(name)) {
341 return element;
342 }
343 }
344 return null;
345 }
346
347 public Element getElement(Element parent_element, String name) {
348 DebugStream.println("Get element named " + name + " from " + parent_element.getAttribute("name"));
349 NodeList elements = parent_element.getElementsByTagName("Element");
350 for(int i = 0; i < elements.getLength(); i++) {
351 Element element = (Element) elements.item(i);
352 if(element.getAttribute("name").equals(name) && element.getParentNode() == parent_element) {
353 elements = null;
354 return element;
355 }
356 }
357 elements = null;
358 return null;
359 }
360 /** Method to acquire a list of all the elements in this metadata set.
361 * @return A <strong>NodeList</strong> containing all of this sets elements.
362 */
363 public NodeList getElements() {
364 return elements;
365 }
366
367 /** Method to retrieve a list of all the elements in this metadata set, sorted.
368 * @return A <strong>Vector</strong> containing all of the elements of this sets, sorted.
369 */
370 public Vector getElementsSorted() {
371 Vector elements_list = new Vector();
372 for (int i = 0; i < elements.getLength(); i++) {
373 elements_list.add(new ElementWrapper((Element) elements.item(i)));
374 }
375 Collections.sort(elements_list, MSMUtils.METADATA_COMPARATOR);
376 return elements_list;
377 }
378
379 /** Method to retrieve the original file this metadata set was created from.
380 * @return A <strong>File</strong>.
381 */
382 public File getFile() {
383 return file;
384 }
385 /** Get the last changed attribute.
386 * @return Last changed as a <strong>String</strong>.
387 */
388 public String getLastChanged() {
389 return root.getAttribute("lastchanged");
390 }
391 /** Method to get this metadata sets name. Note that this is language specific, so we determine the desired language from the Dictionary. If no such entry exists, first try returning the english version and failing that the first name found.
392 * @return A <strong>String</strong> which contains its name.
393 */
394 public String getName() {
395 if(current_language_code != null && !Configuration.getLanguage().equals(current_language_code)) {
396 name = null;
397 }
398 if(name == null) {
399 name = getAttribute(StaticStrings.NAME_ELEMENT, Dictionary.get("MSM.No_Name"));
400 }
401 return name;
402 }
403 /** Method to retrieve this metadata sets namespace.
404 * @return The namespace as a <strong>String</strong>.
405 */
406 public String getNamespace() {
407 return root.getAttribute("namespace");
408 }
409 /** Method to retrieve the root element, i.e. the Document Element, of the DOM model behind this metadata set.
410 * @return An <strong>Element</strong> which is at the root of the modal.
411 */
412 public Element getRoot() {
413 return root;
414 }
415 /** Retrieve the value tree from this set that matches the given element.
416 * @param element The target <strong>ElementWrapper</strong>.
417 * @return A <strong>GValueModel</strong> value tree, or <i>null</i> if no such element or value tree.
418 */
419 public GValueModel getValueTree(ElementWrapper element) {
420 GValueModel value_tree = null;
421 // Stinking hashtable get doesn't use the overridden equals. So I'll do a loop, which should be pretty small ie O(n) for n metadata elements.
422 for(Enumeration keys = value_trees.keys(); keys.hasMoreElements(); ) {
423 ElementWrapper sibling = (ElementWrapper) keys.nextElement();
424 if(sibling.equals(element)) {
425 value_tree = (GValueModel) value_trees.get(sibling);
426 break;
427 }
428 }
429 // If we've found no value tree, create a new one.
430 if(value_tree == null) {
431 value_tree = new GValueModel(element);
432 value_trees.put(element, value_tree);
433 }
434 return value_tree;
435 }
436 /** Remove a mds level attribute.
437 * @param name The name of the attribute to remove.
438 */
439 public void removeAttribute(String name) {
440 root.removeAttribute(name);
441 }
442 /** Method to remove the given element from this metadata set.
443 * @param element The <strong>Element</strong> to be removed.
444 */
445 public void removeElement(Element element) {
446 // we need to remove the value tree too!!
447 removeValueTree(new ElementWrapper(element));
448 root.removeChild(element);
449 }
450 /** Used to remove the value tree for a specific element.
451 * @param element The <strong>ElementWrapper</strong> whose tree you wish to remove.
452 * @return The <strong>GValueModel</strong> we just removed
453 */
454 public GValueModel removeValueTree(ElementWrapper element) {
455 for(Enumeration keys = value_trees.keys(); keys.hasMoreElements(); ) {
456 ElementWrapper sibling = (ElementWrapper) keys.nextElement();
457 if(sibling.equals(element)) {
458 GValueModel value_tree = (GValueModel) value_trees.get(sibling);
459 value_trees.remove(sibling);
460 return value_tree;
461 }
462 }
463 return null;
464 }
465 /** Set one of the mds level attributes.
466 * @param name The attribute to change.
467 * @param value its new value.
468 */
469 public void setAttribute(String name, String value) {
470 root.setAttribute(name, value);
471 }
472 /** Once the metadata set has been saved to a different location, this is used to update the file parameter.
473 * @param file The new location of this metadata set <strong>File</strong>.
474 */
475 public void setFile(File file) {
476 this.file = file;
477 }
478
479 public void setName(String name) {
480 // Retrieve the name element. We look for the first english one.
481 Element name_element = null;
482 Element metadataset_element = document.getDocumentElement();
483 NodeList name_elements = metadataset_element.getElementsByTagName(Utility.NAME_ELEMENT);
484 for(int i = 0; i < name_elements.getLength(); i++) {
485 Element possible_name_element = (Element) name_elements.item(i);
486 if(possible_name_element.getAttribute(Utility.LANGUAGE_ATTRIBUTE).equals(Utility.ENGLISH_VALUE)) {
487 // Found it.
488 name_element = possible_name_element;
489 }
490 }
491 // If there is none add one. Note that we can only add english metadata sets. Although others can edit them to add further names as necessary.
492 if(name_element == null) {
493 name_element = document.createElement(Utility.NAME_ELEMENT);
494 name_element.setAttribute(Utility.LANGUAGE_ATTRIBUTE, Utility.ENGLISH_VALUE);
495 metadataset_element.insertBefore(name_element, metadataset_element.getFirstChild());
496 }
497 // Replace the text node
498 while(name_element.hasChildNodes()) {
499 name_element.removeChild(name_element.getFirstChild());
500 }
501 name_element.appendChild(document.createTextNode(name));
502 }
503
504 /** Method to determine the number of elements in this set.
505 * @return An <i>int</i> specifying the element count.
506 */
507 public int size() {
508 return elements.getLength();
509 }
510 /** Method to translate this class into a meaningful string, which in this case is the metadata sets name.
511 * @return The metadata sets name as a <strong>String</strong>.
512 */
513 public String toString() {
514 String name = getName();
515 // If there is no given name, then use the namespace as there is garaunteed to be one of them.
516 if(name == null || name.length() == 0) {
517 name = root.getAttribute("namespace");
518 }
519 // Append namespace
520 String namespace = root.getAttribute("namespace");
521 if(namespace == null || namespace.equals("")) {
522 namespace = Utility.EXTRACTED_METADATA_NAMESPACE;
523 }
524 name = name + " (" + namespace + ")";
525 return name;
526 }
527
528 /** This method retrieves the required attribute from the Metadata Set, typically it's name or it's description. Note that this method is language dependant, and moreover supports both legacy metadata sets and the new sets optimized for multiple languages.
529 * @param element_name the name of the type of element the required information is in as a String
530 * @param default_string the value to return if no such element is found also as a String
531 * @see org.greenstone.gatherer.Configuration#getLanguage()
532 * @see org.greenstone.gatherer.Gatherer#config
533 * @see org.greenstone.gatherer.msm.MSMUtils#getValue(Node)
534 * @see org.greenstone.gatherer.util.StaticStrings#CODE_ATTRIBUTE
535 * @see org.greenstone.gatherer.util.StaticStrings#SETLANGUAGE_ELEMENT
536 */
537 private String getAttribute(String element_name, String default_string) {
538 String result = null;
539
540 // Determine the language code.
541 current_language_code = Configuration.getLanguage();
542
543 ///ystem.err.println("Searching for the " + element_name + " in " + current_language_code);
544
545 // New Metadata Set Format makes use of deferred-node-expansion to save memory - rather than create nodes for a name and description in each language, nodes which have potentially huge strings, we instead create simplier SETLANGUAGE nodes, and then only expand the one in the desired language. Of course if a user happens to change to every available language slightly more memory will be used than in the old method. For instance consider the DLS with 25 languages, each with a name node of 50 bytes and an descriptions of 500. Thus old style > 13750 bytes while new style < 600.
546 NodeList set_language_elements = document.getElementsByTagName(StaticStrings.SETLANGUAGE_ELEMENT);
547 for(int b = 0; b < set_language_elements.getLength(); b++) {
548 Element set_language_element = (Element) set_language_elements.item(b);
549 String code = set_language_element.getAttribute(StaticStrings.CODE_ATTRIBUTE).toLowerCase();
550 if(code.equals(current_language_code)) {
551 NodeList specific_elements = set_language_element.getElementsByTagName(element_name);
552 if(specific_elements.getLength() > 0) {
553 Element specific_element = (Element) specific_elements.item(0);
554 result = MSMUtils.getValue(specific_element);
555 specific_element = null;
556 }
557 specific_elements = null;
558 }
559 code = null;
560 set_language_element = null;
561 }
562 set_language_elements = null;
563 // And we may be all done
564 if(result != null) {
565 return result;
566 }
567
568 // Failing that we move on to an older style search - start by recovering all Name elements
569 NodeList possible_elements = document.getElementsByTagName(element_name);
570 // Iterate through the available names looking for the appropriate one. Also make note of the first name, then overwrite it with any english one.
571 boolean found = false;
572 for(int i = 0; !found && i < possible_elements.getLength(); i++) {
573 Element possible_element = (Element) possible_elements.item(i);
574 String possible_element_code = possible_element.getAttribute("language").toLowerCase();
575 if(possible_element_code.equals(current_language_code) || name == null) {
576 result = MSMUtils.getValue(possible_element);
577 found = true;
578 }
579 possible_element_code = null;
580 possible_element = null;
581 }
582 possible_elements = null;
583 // Failing all that set an error message
584 if(result == null) {
585 result = default_string;
586 }
587 return result;
588 }
589
590 private void init(boolean use_classloader) {
591
592 if(this.document != null) {
593 this.elements = document.getElementsByTagName("Element");
594 this.root = document.getDocumentElement();
595 // Now for each element read in its value tree if present.
596 for(int i = elements.getLength() - 1; i >= 0; i--) {
597 ElementWrapper value_element = new ElementWrapper((Element)elements.item(i));
598 File value_file = new File(file.getParentFile(), value_element.getName() + ".mdv");
599 ///ystem.err.println("Searching for " + value_file.getAbsolutePath());
600 if(value_file.exists()) {
601 Document value_document;
602 if (use_classloader) {
603 value_document = Utility.parse(value_file.toString(), true);
604 }
605 else {
606 value_document = Utility.parse(value_file, false);
607 }
608 if(value_document != null) {
609 value_trees.put(value_element, new GValueModel(value_element, value_document));
610 }
611 else {
612 DebugStream.println("Error! Missing mdv file: " + value_file.getAbsolutePath());
613 }
614 }
615 }
616 }
617 else {
618 DebugStream.println("Error! Missing mds file: " + file.getAbsolutePath());
619 }
620 }
621}
Note: See TracBrowser for help on using the repository browser.