source: FCSSimpleEndpoint/tags/FCSSimpleEndpoint-1.3.0/src/main/java/eu/clarin/sru/server/fcs/utils/SimpleEndpointDescriptionParser.java @ 6957

Last change on this file since 6957 was 6957, checked in by Oliver Schonefeld, 8 years ago
  • tag version 1.3.0
  • Property svn:eol-style set to native
File size: 29.3 KB
Line 
1/**
2 * This software is copyright (c) 2013-2016 by
3 *  - Institut fuer Deutsche Sprache (http://www.ids-mannheim.de)
4 * This is free software. You can redistribute it
5 * and/or modify it under the terms described in
6 * the GNU General Public License v3 of which you
7 * should have received a copy. Otherwise you can download
8 * it from
9 *
10 *   http://www.gnu.org/licenses/gpl-3.0.txt
11 *
12 * @copyright Institut fuer Deutsche Sprache (http://www.ids-mannheim.de)
13 *
14 * @license http://www.gnu.org/licenses/gpl-3.0.txt
15 *  GNU General Public License v3
16 */
17package eu.clarin.sru.server.fcs.utils;
18
19import java.io.IOException;
20import java.net.URI;
21import java.net.URISyntaxException;
22import java.net.URL;
23import java.util.ArrayList;
24import java.util.HashMap;
25import java.util.HashSet;
26import java.util.Iterator;
27import java.util.List;
28import java.util.Map;
29import java.util.Set;
30
31import javax.xml.XMLConstants;
32import javax.xml.namespace.NamespaceContext;
33import javax.xml.parsers.DocumentBuilder;
34import javax.xml.parsers.DocumentBuilderFactory;
35import javax.xml.parsers.ParserConfigurationException;
36import javax.xml.xpath.XPath;
37import javax.xml.xpath.XPathConstants;
38import javax.xml.xpath.XPathExpression;
39import javax.xml.xpath.XPathExpressionException;
40import javax.xml.xpath.XPathFactory;
41
42import org.slf4j.Logger;
43import org.slf4j.LoggerFactory;
44import org.w3c.dom.Document;
45import org.w3c.dom.Element;
46import org.w3c.dom.Node;
47import org.w3c.dom.NodeList;
48import org.xml.sax.SAXException;
49
50import eu.clarin.sru.server.SRUConfigException;
51import eu.clarin.sru.server.fcs.DataView;
52import eu.clarin.sru.server.fcs.DataView.DeliveryPolicy;
53import eu.clarin.sru.server.fcs.EndpointDescription;
54import eu.clarin.sru.server.fcs.Layer;
55import eu.clarin.sru.server.fcs.ResourceInfo;
56
57
58/**
59 * A parser, that parses an XML file and produces a endpoint description with
60 * static list of resource info records. The XML file has the same format as the
61 * result format defined for endpoint description of the CLARIN-FCS
62 * specification. The {@link #parse(URL)} returns a
63 * {@link SimpleEndpointDescription} instance.
64 *
65 * @see EndpointDescription
66 * @see SimpleEndpointDescription
67 */
68public class SimpleEndpointDescriptionParser {
69    private static final String NS =
70            "http://clarin.eu/fcs/endpoint-description";
71    private static final String NS_LEGACY =
72            "http://clarin.eu/fcs/1.0/resource-info";
73    private static final URI CAP_BASIC_SEARCH =
74            URI.create("http://clarin.eu/fcs/capability/basic-search");
75    private static final URI CAP_ADVANCED_SEARCH =
76            URI.create("http://clarin.eu/fcs/capability/advanced-search");
77    private static final String MINETYPE_HITS = "application/x-clarin-fcs-hits+xml";
78    private static final String MINETYPE_ADV = "application/x-clarin-fcs-adv+xml";
79    private static final String LANG_EN = "en";
80    private static final String POLICY_SEND_DEFAULT = "send-by-default";
81    private static final String POLICY_NEED_REQUEST = "need-to-request";
82    private static final String LAYER_ENCODING_VALUE = "value";
83    private static final String LAYER_ENCODING_EMPTY = "empty";
84    private static final Logger logger =
85            LoggerFactory.getLogger(SimpleEndpointDescriptionParser.class);
86
87
88    /**
89     * Parse an XML file and return a static list of resource info records.
90     *
91     * @param url
92     *            the URI pointing to the file to be parsed
93     * @return an {@link EndpointDescription} instance
94     * @throws SRUConfigException
95     *             if an error occurred
96     */
97    public static EndpointDescription parse(URL url) throws SRUConfigException {
98        if (url == null) {
99            throw new NullPointerException("url == null");
100        }
101
102        logger.debug("parsing endpoint description from: {}", url);
103
104        try {
105            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
106            dbf.setNamespaceAware(true);
107            dbf.setCoalescing(true);
108            DocumentBuilder db = dbf.newDocumentBuilder();
109            Document doc = db.parse(url.openStream());
110
111            /*
112             * Detect for deprecated resource-info catalog files and bail, if necessary
113             */
114            checkLegacyMode(doc, url);
115
116            /*
117             * Parse on and create endpoint description ...
118             */
119            return parseEndpointDescription(doc);
120        } catch (ParserConfigurationException e) {
121            throw new SRUConfigException("internal error", e);
122        } catch (SAXException e) {
123            throw new SRUConfigException("parsing error", e);
124        } catch (IOException e) {
125            throw new SRUConfigException("error reading file", e);
126        } catch (XPathExpressionException e) {
127            throw new SRUConfigException("internal error", e);
128        }
129    }
130
131
132    private static EndpointDescription parseEndpointDescription(Document doc)
133            throws SRUConfigException, XPathExpressionException {
134        XPathFactory factory = XPathFactory.newInstance();
135        XPath xpath = factory.newXPath();
136
137        xpath.setNamespaceContext(new NamespaceContext() {
138            @Override
139            public Iterator<?> getPrefixes(String namespaceURI) {
140                throw new UnsupportedOperationException();
141            }
142
143            @Override
144            public String getPrefix(String namespaceURI) {
145                throw new UnsupportedOperationException();
146            }
147
148            @Override
149            public String getNamespaceURI(String prefix) {
150                if (prefix == null) {
151                    throw new NullPointerException("prefix == null");
152                }
153                if (prefix.equals("ed")) {
154                    return NS;
155                } else if (prefix.equals(XMLConstants.XML_NS_PREFIX)) {
156                    return XMLConstants.XML_NS_URI;
157                } else {
158                    return XMLConstants.NULL_NS_URI;
159                }
160            }
161        });
162
163        // capabilities
164        List<URI> capabilities = new ArrayList<URI>();
165        XPathExpression exp =
166                xpath.compile("//ed:Capabilities/ed:Capability");
167        NodeList list =
168                (NodeList) exp.evaluate(doc, XPathConstants.NODESET);
169        if ((list != null) && (list.getLength() > 0)) {
170            logger.debug("parsing capabilities");
171            for (int i = 0; i < list.getLength(); i++) {
172                String s = list.item(i).getTextContent().trim();
173                try {
174                    URI uri = new URI(s);
175                    if (!capabilities.contains(uri)) {
176                        capabilities.add(uri);
177                    } else {
178                        logger.warn("ignoring duplicate capability " +
179                                "entry for '{}'", uri);
180                    }
181                } catch (URISyntaxException e) {
182                    throw new SRUConfigException("capability is not encoded " +
183                            "as proper URI: " + s);
184                }
185            }
186        } else {
187            logger.warn("No capabilities where defined in " +
188                    "endpoint configuration");
189        }
190        if (!capabilities.contains(CAP_BASIC_SEARCH)) {
191            logger.warn("capability '{}' was not defined in endpoint " +
192                    "description; added it to meet specification. Please " +
193                    "update your endpoint description!", CAP_BASIC_SEARCH);
194            capabilities.add(CAP_BASIC_SEARCH);
195        }
196        logger.debug("CAPS:'{}'", capabilities);
197
198        // used to check for id attribute uniqueness
199        final Set<String> xml_ids = new HashSet<String>();
200
201        // supported data views
202        List<DataView> supportedDataViews = new ArrayList<DataView>();
203        exp = xpath.compile("//ed:SupportedDataViews/ed:SupportedDataView");
204        list = (NodeList) exp.evaluate(doc, XPathConstants.NODESET);
205        if ((list != null) && (list.getLength() > 0)) {
206            logger.debug("parsing supported data views");
207            for (int i = 0; i < list.getLength(); i++) {
208                Element item = (Element) list.item(i);
209                String id = getAttribute(item, "id");
210                if (id == null) {
211                    throw new SRUConfigException("Element <SupportedDataView> "
212                            + "must carry a proper 'id' attribute");
213                }
214
215                if (xml_ids.contains(id)) {
216                    throw new SRUConfigException("The value of attribute " +
217                            "'id' of element <SupportedDataView> must be unique: " + id);
218                }
219                xml_ids.add(id);
220
221                String p = getAttribute(item, "delivery-policy");
222                if (p == null) {
223                    throw new SRUConfigException("Element <SupportedDataView> "
224                            + "must carry a 'delivery-policy' attribute");
225                }
226                DeliveryPolicy policy = null;
227                if (POLICY_SEND_DEFAULT.equals(p)) {
228                    policy = DeliveryPolicy.SEND_BY_DEFAULT;
229                } else if (POLICY_NEED_REQUEST.equals(p)) {
230                    policy = DeliveryPolicy.NEED_TO_REQUEST;
231                } else {
232                    throw new SRUConfigException("Invalid value '" + p +
233                            "' for attribute 'delivery-policy' on element " +
234                            "<SupportedDataView>");
235                }
236                String mimeType = item.getTextContent();
237                if (mimeType != null) {
238                    mimeType = mimeType.trim();
239                    if (mimeType.isEmpty()) {
240                        mimeType = null;
241                    }
242                }
243                if (mimeType == null) {
244                    throw new SRUConfigException("Element <SupportedDataView> "
245                            + "must contain a MIME-type as content");
246                }
247                // check for duplicate entries ...
248                for (DataView dataView : supportedDataViews) {
249                    if (id.equals(dataView.getIdentifier())) {
250                        throw new SRUConfigException(
251                                "A <SupportedDataView> with " + "the id '" +
252                                        id + "' is already defined!");
253                    }
254                    if (mimeType.equals(dataView.getMimeType())) {
255                        throw new SRUConfigException(
256                                "A <SupportedDataView> with " +
257                                        "the MIME-type '" + mimeType +
258                                        "' is already defined!");
259                    }
260                }
261                supportedDataViews.add(new DataView(id, mimeType, policy));
262            }
263        } else {
264            logger.error("Endpoint configuration contains no valid " +
265                    "information about supported data views");
266            throw new SRUConfigException("Endpoint configuration contains " +
267                    "no valid information about supported data views");
268        }
269
270        logger.debug("DV: {}", supportedDataViews);
271
272        // sanity check on data views
273        boolean hasHitsView = false;
274        boolean hasAdvView = false;
275
276        for (DataView dataView : supportedDataViews) {
277            if (dataView.getMimeType().equals(MINETYPE_HITS)) {
278                hasHitsView = true;
279            } else if (dataView.getMimeType().equals(MINETYPE_ADV)) {
280                hasAdvView = true;
281            }
282        }
283        if (!hasHitsView) {
284            throw new SRUConfigException("Generic Hits Data View (" +
285                    MINETYPE_HITS + ") was not declared in <SupportedDataViews>");
286        }
287        if (capabilities.contains(CAP_ADVANCED_SEARCH) && !hasAdvView) {
288            throw new SRUConfigException("Endpoint claimes to support " +
289                    "Advanced FCS but does not declare Advanced Data View (" +
290                    MINETYPE_ADV + ") in <SupportedDataViews>");
291
292        }
293
294
295        // supported layers
296        List<Layer> supportedLayers = null;
297        exp = xpath.compile("//ed:SupportedLayers/ed:SupportedLayer");
298        list = (NodeList) exp.evaluate(doc, XPathConstants.NODESET);
299        if ((list != null) && (list.getLength() > 0)) {
300            logger.debug("parsing supported layers");
301            for (int i = 0; i < list.getLength(); i++) {
302                Element item = (Element) list.item(i);
303                String id = getAttribute(item, "id");
304                if (id == null) {
305                    throw new SRUConfigException("Element <SupportedLayer> "
306                            + "must carry a proper 'id' attribute");
307                }
308
309                if (xml_ids.contains(id)) {
310                    throw new SRUConfigException("The value of attribute " +
311                            "'id' of element <SupportedLayer> must be unique: " + id);
312                }
313                xml_ids.add(id);
314
315                String s = getAttribute(item, "result-id");
316                if (s == null) {
317                    throw new SRUConfigException("Element <SupportedLayer> "
318                            + "must carry a proper 'result-id' attribute");
319                }
320                URI resultId = null;
321                try {
322                    resultId = new URI(s);
323                } catch (URISyntaxException e) {
324                    throw new SRUConfigException("Attribute 'result-id' on " +
325                            "Element <SupportedLayer> is not encoded " +
326                            "as proper URI: " + s);
327                }
328
329                String type = cleanString(item.getTextContent());
330                if ((type != null) && !type.isEmpty()) {
331                    // sanity check on layer types
332                    if (!(type.equals("text") ||
333                            type.equals("lemma") ||
334                            type.equals("pos") ||
335                            type.equals("orth") ||
336                            type.equals("norm") ||
337                            type.equals("phonetic") ||
338                            type.startsWith("x-"))) {
339                        logger.warn("layer type '{}' is not defined by specification", type);
340                    }
341                } else {
342                    throw new SRUConfigException("Element <SupportedLayer> " +
343                            "does not define a proper layer type");
344                }
345
346                String qualifier = getAttribute(item, "qualifier");
347
348                Layer.ContentEncoding encoding =
349                        Layer.ContentEncoding.VALUE;
350                s = getAttribute(item, "type");
351                if (s != null) {
352                    if (LAYER_ENCODING_VALUE.equals(s)) {
353                        encoding = Layer.ContentEncoding.VALUE;
354                    } else if (LAYER_ENCODING_EMPTY.equals(s)) {
355                        encoding = Layer.ContentEncoding.EMPTY;
356                    } else {
357                        throw new SRUConfigException("invalid layer encoding: " + s);
358                    }
359                }
360
361
362                String altValueInfo = getAttribute(item, "alt-value-info");
363                URI altValueInfoURI = null;
364                if (altValueInfo != null) {
365                    s = getAttribute(item, "alt-value-info-uri");
366                    if (s != null) {
367                        try {
368                          altValueInfoURI = new URI(s);
369                        } catch (URISyntaxException e) {
370                            throw new SRUConfigException("Attribute 'alt-value-info-uri' on " +
371                                    "Element <SupportedLayer> is not encoded " +
372                                    "as proper URI: " + s);
373                        }
374                    } else {
375
376                    }
377                }
378
379
380
381                if (supportedLayers == null) {
382                    supportedLayers = new ArrayList<Layer>(list.getLength());
383                }
384                supportedLayers.add(new Layer(id, resultId, type, encoding,
385                        qualifier, altValueInfo, altValueInfoURI));
386            }
387        }
388
389        if ((supportedLayers != null) &&
390                !capabilities.contains(CAP_ADVANCED_SEARCH)) {
391                logger.warn("capability '{}' was not defined in endpoint " +
392                        "description; added it to meet specification. Please " +
393                        "update your endpoint description!", CAP_ADVANCED_SEARCH);
394                capabilities.add(CAP_ADVANCED_SEARCH);
395        }
396        logger.debug("L: {}", supportedLayers);
397
398        // resources
399        exp = xpath.compile("/ed:EndpointDescription/ed:Resources/ed:Resource");
400        list = (NodeList) exp.evaluate(doc, XPathConstants.NODESET);
401        final Set<String> pids = new HashSet<String>();
402        List<ResourceInfo> resources = parseRessources(xpath, list, pids,
403                supportedDataViews, supportedLayers, hasAdvView);
404        if ((resources == null) || resources.isEmpty()) {
405            throw new SRUConfigException("No resources where " +
406                    "defined in endpoint description");
407        }
408
409        return new SimpleEndpointDescription(capabilities,
410                supportedDataViews,
411                supportedLayers,
412                resources,
413                false);
414    }
415
416
417    private static List<ResourceInfo> parseRessources(XPath xpath,
418            NodeList nodes, Set<String> pids, List<DataView> supportedDataViews,
419            List<Layer> supportedLayers, boolean hasAdv)
420                    throws SRUConfigException, XPathExpressionException {
421        List<ResourceInfo> ris = null;
422      for (int k = 0; k < nodes.getLength(); k++) {
423          final Element node                = (Element) nodes.item(k);
424          String pid                        = null;
425          Map<String, String> titles        = null;
426          Map<String, String> descrs        = null;
427          String link                       = null;
428          List<String> langs                = null;
429          List<DataView> availableDataViews = null;
430          List<Layer> availableLayers       = null;
431          List<ResourceInfo> sub            = null;
432
433          pid = getAttribute(node, "pid");
434          if (pid == null) {
435              throw new SRUConfigException("Element <ResourceInfo> " +
436                      "must carry a proper 'pid' attribute");
437          }
438          if (pids.contains(pid)) {
439              throw new SRUConfigException("Another element <Resource> " +
440                      "with pid '" + pid + "' already exists");
441          }
442          pids.add(pid);
443
444          XPathExpression exp = xpath.compile("ed:Title");
445          NodeList list = (NodeList) exp.evaluate(node, XPathConstants.NODESET);
446          if ((list != null) && (list.getLength() > 0)) {
447              for (int i = 0; i < list.getLength(); i++) {
448                  final Element n = (Element) list.item(i);
449
450                  final String lang = getLangAttribute(n);
451                  if (lang == null) {
452                      throw new SRUConfigException("Element <Title> must " +
453                              "carry a proper 'xml:lang' attribute");
454                  }
455
456                  final String title = cleanString(n.getTextContent());
457                  if (title == null) {
458                      throw new SRUConfigException("Element <Title> must " +
459                              "carry a non-empty 'xml:lang' attribute");
460                  }
461
462                  if (titles == null) {
463                      titles = new HashMap<String, String>();
464                  }
465                  if (titles.containsKey(lang)) {
466                      logger.warn("title with language '{}' already exists",
467                              lang);
468                  } else {
469                      logger.debug("title: '{}' '{}'", lang, title);
470                      titles.put(lang, title);
471                  }
472              }
473              if ((titles != null) && !titles.containsKey(LANG_EN)) {
474                  throw new SRUConfigException(
475                          "A <Title> with language 'en' is mandatory");
476              }
477          }
478
479          exp = xpath.compile("ed:Description");
480          list = (NodeList) exp.evaluate(node, XPathConstants.NODESET);
481          if ((list != null) && (list.getLength() > 0)) {
482              for (int i = 0; i < list.getLength(); i++) {
483                  Element n = (Element) list.item(i);
484
485                  String lang = getLangAttribute(n);
486                  if (lang == null) {
487                      throw new SRUConfigException("Element <Description> " +
488                              "must carry a proper 'xml:lang' attribute");
489
490                  }
491                  String desc = cleanString(n.getTextContent());
492
493                  if (descrs == null) {
494                      descrs = new HashMap<String, String>();
495                  }
496
497                  if (descrs.containsKey(lang)) {
498                      logger.warn("description with language '{}' "
499                              + "already exists", lang);
500                  } else {
501                      logger.debug("description: '{}' '{}'", lang, desc);
502                      descrs.put(lang, desc);
503                  }
504              }
505              if ((descrs != null) && !descrs.containsKey(LANG_EN)) {
506                  throw new SRUConfigException(
507                          "A <Description> with language 'en' is mandatory");
508              }
509          }
510
511          exp = xpath.compile("ed:LandingPageURI");
512          list = (NodeList) exp.evaluate(node, XPathConstants.NODESET);
513          if ((list != null) && (list.getLength() > 0)) {
514              for (int i = 0; i < list.getLength(); i++) {
515                  Element n = (Element) list.item(i);
516                  link = cleanString(n.getTextContent());
517              }
518          }
519
520          exp = xpath.compile("ed:Languages/ed:Language");
521          list = (NodeList) exp.evaluate(node, XPathConstants.NODESET);
522          if ((list != null) && (list.getLength() > 0)) {
523              for (int i = 0; i < list.getLength(); i++) {
524                  Element n = (Element) list.item(i);
525
526                  String s = n.getTextContent();
527                  if (s != null) {
528                      s = s.trim();
529                      if (s.isEmpty()) {
530                          s = null;
531                      }
532                  }
533
534                  /*
535                   * enforce three letter codes
536                   */
537                  if ((s == null) || (s.length() != 3)) {
538                      throw new SRUConfigException("Element <Language> " +
539                              "must use ISO-632-3 three letter " +
540                              "language codes");
541                  }
542
543                  if (langs == null) {
544                      langs = new ArrayList<String>();
545                  }
546                  langs.add(s);
547              }
548          }
549
550          exp = xpath.compile("ed:AvailableDataViews");
551          Node n = (Node) exp.evaluate(node, XPathConstants.NODE);
552          if ((n != null) && (n instanceof Element)) {
553              String ref = getAttribute((Element) n, "ref");
554              if (ref == null) {
555                  throw new SRUConfigException("Element <AvailableDataViews> " +
556                          "must carry a 'ref' attribute");
557              }
558              String[] refs = ref.split("\\s+");
559              if ((refs == null) || (refs.length < 1)) {
560                  throw new SRUConfigException("Attribute 'ref' on element " +
561                          "<AvailableDataViews> must contain a whitespace " +
562                          "seperated list of data view references");
563              }
564
565
566              for (int i = 0; i < refs.length; i++) {
567                  DataView dataview = null;
568                  for (DataView dv : supportedDataViews) {
569                      if (refs[i].equals(dv.getIdentifier())) {
570                          dataview = dv;
571                          break;
572                      }
573                  }
574                  if (dataview != null) {
575                      if (availableDataViews == null) {
576                          availableDataViews = new ArrayList<DataView>();
577                      }
578                      availableDataViews.add(dataview);
579                  } else {
580                      throw new SRUConfigException("A data view with " +
581                              "identifier '" + refs[i] + "' was not defined " +
582                              "in <SupportedDataViews>");
583                  }
584              }
585          } else {
586              throw new SRUConfigException(
587                      "missing element <AvailableDataViews>");
588          }
589          if (availableDataViews == null) {
590              throw new SRUConfigException("No available data views where " +
591                      "defined for resource with PID '" + pid + "'");
592          }
593
594          exp = xpath.compile("ed:AvailableLayers");
595          n = (Node) exp.evaluate(node, XPathConstants.NODE);
596          if ((n != null) && (n instanceof Element)) {
597              String ref = getAttribute((Element) n, "ref");
598              if (ref == null) {
599                  throw new SRUConfigException("Element <AvailableLayers> " +
600                          "must carry a 'ref' attribute");
601              }
602              String[] refs = ref.split("\\s+");
603              if ((refs == null) || (refs.length < 1)) {
604                  throw new SRUConfigException("Attribute 'ref' on element " +
605                          "<AvailableLayers> must contain a whitespace " +
606                          "seperated list of data view references");
607              }
608
609
610              for (int i = 0; i < refs.length; i++) {
611                  Layer layer = null;
612                  for (Layer l : supportedLayers) {
613                      if (refs[i].equals(l.getId())) {
614                          layer = l;
615                          break;
616                      }
617                  }
618                  if (layer != null) {
619                      if (availableLayers == null) {
620                          availableLayers = new ArrayList<Layer>();
621                      }
622                      availableLayers.add(layer);
623                  } else {
624                      throw new SRUConfigException("A layer with " +
625                              "identifier '" + refs[i] + "' was not defined " +
626                              "in <SupportedLayers>");
627                  }
628              }
629          } else {
630              if (hasAdv) {
631                  logger.debug("no <SupportedLayers> for ressource '{}'", pid);
632              }
633          }
634
635          exp = xpath.compile("ed:Resources/ed:Resource");
636          list = (NodeList) exp.evaluate(node, XPathConstants.NODESET);
637          if ((list != null) && (list.getLength() > 0)) {
638              sub = parseRessources(xpath, list, pids,
639                      supportedDataViews, supportedLayers, hasAdv);
640          }
641
642          if (ris == null) {
643              ris = new ArrayList<ResourceInfo>();
644          }
645          ris.add(new ResourceInfo(pid,
646                  titles,
647                  descrs,
648                  link,
649                  langs,
650                  availableDataViews,
651                  availableLayers,
652                  sub));
653      }
654      return ris;
655    }
656
657
658    private static String getAttribute(Element el, String localName) {
659        String value = el.getAttribute(localName);
660        if (value != null) {
661            value = value.trim();
662            if (!value.isEmpty()) {
663                return value;
664            }
665        }
666        return null;
667    }
668
669
670    private static String getLangAttribute(Element el) {
671        String lang = el.getAttributeNS(XMLConstants.XML_NS_URI, "lang");
672        if (lang != null) {
673            lang = lang.trim();
674            if (!lang.isEmpty()) {
675                return lang;
676            }
677        }
678        return null;
679    }
680
681
682    private static String cleanString(String s) {
683        if (s != null) {
684            s = s.trim();
685            if (!s.isEmpty()) {
686                StringBuilder sb = new StringBuilder();
687                for (String z : s.split("\\s*\\n+\\s*")) {
688                    z = z.trim();
689                    if (!z.isEmpty()) {
690                        if (sb.length() > 0) {
691                            sb.append(' ');
692                        }
693                        sb.append(z);
694                    }
695                }
696                if (sb.length() > 0) {
697                    return sb.toString();
698                }
699            }
700        }
701        return null;
702    }
703
704
705    private static void checkLegacyMode(Document doc, URL url)
706            throws SRUConfigException {
707        Element root = doc.getDocumentElement();
708        if (root != null) {
709            String ns = root.getNamespaceURI();
710            if (ns != null) {
711                if (ns.equals(NS_LEGACY)) {
712                    logger.error("Detected out-dated " +
713                            "resource info catalog file '" + url +
714                            "'. Please update to the " +
715                            "current version");
716                    throw new SRUConfigException("unsupport file format: " + ns);
717                } else if (!ns.equals(NS)) {
718                    logger.error("Detected unsupported resource info " +
719                            "catalog file '" + url + "' with namespace '" + ns + '"');
720                    throw new SRUConfigException("unsupport file format: " + ns);
721                }
722            } else {
723                throw new SRUConfigException("No namespace URI was detected " +
724                        "for resource info catalog file '" + url +"'!");
725            }
726        } else {
727            throw new SRUConfigException("Error retrieving root element");
728        }
729    }
730
731} // class SimpleResourceInfoInventoryParser
Note: See TracBrowser for help on using the repository browser.