/**
   * Parse Attribution
   *
   * @param layerElem
   * @return Attribution
   * @throws XMLParsingException
   */
  protected Attribution parseAttribution(Element layerElem) throws XMLParsingException {
    LOG.entering();

    Attribution attribution = null;
    Node node = XMLTools.getNode(layerElem, "./Attribution", nsContext);
    if (node != null) {
      String title = XMLTools.getRequiredNodeAsString(layerElem, "./Attribution/Title", nsContext);
      Node onlineR = XMLTools.getRequiredNode(node, "./OnlineResource", nsContext);
      OnlineResource onLineResource = parseOnLineResource((Element) onlineR);
      node = XMLTools.getNode(node, "./LogoURL", nsContext);
      LogoURL logoURL = null;
      if (node != null) {
        int width = XMLTools.getRequiredNodeAsInt(node, "./@width", nsContext);
        int height = XMLTools.getRequiredNodeAsInt(node, "./@height", nsContext);
        String format = XMLTools.getRequiredNodeAsString(node, "./Format", nsContext);
        onlineR = XMLTools.getRequiredNode(node, "./OnlineResource", nsContext);
        OnlineResource logoOR = parseOnLineResource((Element) onlineR);
        logoURL = new LogoURL(width, height, format, logoOR.getLinkage().getHref());
      }
      attribution = new Attribution(title, onLineResource.getLinkage().getHref(), logoURL);
    }

    LOG.exiting();
    return attribution;
  }
  /**
   * parses a Delete element contained in a CS-W Transaction.
   *
   * @param element
   * @return the Delete class parsed from the given Delete element.
   * @throws XMLParsingException
   * @throws MissingParameterValueException
   * @throws InvalidParameterValueException
   */
  private Delete parseDelete(Element element)
      throws XMLParsingException, MissingParameterValueException, InvalidParameterValueException {

    LOG.logDebug("parsing CS-W Transaction-Delete");

    String handle = XMLTools.getNodeAsString(element, "@handle", nsContext, null);
    String tmp = XMLTools.getNodeAsString(element, "@typeName", nsContext, null);
    URI typeName = null;
    if (tmp != null) {
      // part of the corrected CS-W 2.0 spec
      try {
        typeName = new URI(tmp);
      } catch (Exception e) {
        throw new XMLParsingException("if defined attribute 'typeName' must be a valid URI");
      }
    }

    Element elem = (Element) XMLTools.getRequiredNode(element, "./csw202:Constraint", nsContext);
    String ver = XMLTools.getNodeAsString(elem, "@version", nsContext, null);
    if (ver == null) {
      String s = Messages.getMessage("CSW_MISSING_CONSTRAINT_VERSION");
      throw new MissingParameterValueException(s);
    }
    if (!"1.0.0".equals(ver) && !"1.1.0".equals(ver)) {
      String s = Messages.getMessage("CSW_INVALID_CONSTRAINT_VERSION", ver);
      throw new InvalidParameterValueException(s);
    }

    elem = (Element) XMLTools.getRequiredNode(elem, "./ogc:Filter", nsContext);

    Filter constraint = AbstractFilter.buildFromDOM(elem, "1.0.0".equals(ver));
    return new Delete(handle, typeName, constraint);
  }
  /**
   * returns WMPS contact informaion encapsulated within a <code>ServiceProvider</code> object
   *
   * @return ServiceProvider
   * @throws XMLParsingException
   */
  protected ServiceProvider parseServiceProvider() throws XMLParsingException {
    LOG.entering();

    SimpleLink sLink = retrieveOnlineResourceSimpleLink();

    LOG.logDebug("Parsing service provider parameter.");
    /**
     * according to WMPS (draft) specification this element is mandatory but there are several
     * services online which does not contain this element in its capabilities
     */
    Node contactInfo =
        XMLTools.getRequiredNode(getRootElement(), "./Service/ContactInformation", nsContext);

    String person =
        XMLTools.getRequiredNodeAsString(
            contactInfo, "./ContactPersonPrimary/ContactPerson", nsContext);
    String orga =
        XMLTools.getRequiredNodeAsString(
            contactInfo, "./ContactPersonPrimary/ContactOrganization", nsContext);
    String position = XMLTools.getRequiredNodeAsString(contactInfo, "./ContactPosition", nsContext);
    ContactInfo contact = parseContactInfo();

    ServiceProvider sp = new ServiceProvider(orga, sLink, person, position, contact, null);

    LOG.exiting();

    return sp;
  }
  /**
   * parses a Update element contained in a CS-W Transaction.
   *
   * @param element
   * @return the update class containing all parsed values
   * @throws XMLParsingException
   * @throws MissingParameterValueException
   * @throws InvalidParameterValueException
   */
  private Update parseUpdate(Element element)
      throws XMLParsingException, MissingParameterValueException, InvalidParameterValueException {

    LOG.logDebug("parsing CS-W Transaction-Update");

    String handle = XMLTools.getNodeAsString(element, "@handle", nsContext, null);
    String tmp = XMLTools.getNodeAsString(element, "@typeName", nsContext, null);
    URI typeName = null;
    if (tmp != null) {
      // part of the corrected CS-W 2.0 spec
      try {
        typeName = new URI(tmp);
      } catch (Exception e) {
        throw new XMLParsingException("if defined attribute 'typeName' must be a valid URI");
      }
    }

    Element elem = (Element) XMLTools.getRequiredNode(element, "./csw202:Constraint", nsContext);
    String ver = XMLTools.getNodeAsString(elem, "@version", nsContext, null);
    if (ver == null) {
      String s = Messages.getMessage("CSW_MISSING_CONSTRAINT_VERSION");
      throw new MissingParameterValueException(s);
    }
    if (!"1.0.0".equals(ver) && !"1.1.0".equals(ver)) {
      String s = Messages.getMessage("CSW_INVALID_CONSTRAINT_VERSION", ver);
      throw new InvalidParameterValueException(s);
    }

    elem = (Element) XMLTools.getRequiredNode(elem, "./ogc:Filter", nsContext);

    Filter constraint = AbstractFilter.buildFromDOM(elem, "1.0.0".equals(ver));

    List<Node> children = null;
    List<Node> rp = XMLTools.getNodes(getRootElement(), "./csw202:RecordProperty", nsContext);
    if (rp.size() != 0) {
      // at the moment will always be null because it is part of the
      // CS-W 2.0 corrected version that will not be implemented yet
    } else {
      children = XMLTools.getNodes(element, "./child::*", nsContext);
      if (children.size() == 0) {
        throw new XMLParsingException("one record must be defined within a CS-W update element");
      }
    }
    return new Update(handle, typeName, constraint, (Element) children.get(0), null);
  }
  /**
   * Parse Style Sheet URL
   *
   * @param node
   * @return StyleSheetURL
   * @throws XMLParsingException
   */
  protected StyleSheetURL parseStyleSheetURL(Node node) throws XMLParsingException {
    LOG.entering();

    StyleSheetURL styleSheetURL = null;
    Node styleNode = XMLTools.getNode(node, "./StyleSheetURL", nsContext);

    if (styleNode != null) {
      String format = XMLTools.getRequiredNodeAsString(styleNode, "./Format", nsContext);
      Element tmp = (Element) XMLTools.getRequiredNode(styleNode, "./OnlineResource", nsContext);
      OnlineResource olr = parseOnLineResource(tmp);
      styleSheetURL = new StyleSheetURL(format, olr.getLinkage().getHref());
    }

    LOG.exiting();
    return styleSheetURL;
  }
  /**
   * Parse AuthorityURL
   *
   * @param layerElem
   * @return AuthorityURL[]
   * @throws XMLParsingException
   */
  protected AuthorityURL[] parseAuthorityURLs(Element layerElem) throws XMLParsingException {
    LOG.entering();

    List nl = XMLTools.getNodes(layerElem, "./AuthorityURL", nsContext);
    AuthorityURL[] authorityURLs = new AuthorityURL[nl.size()];
    for (int i = 0; i < authorityURLs.length; i++) {
      String name = XMLTools.getRequiredNodeAsString((Node) nl.get(i), "./@name", nsContext);
      Element tmp =
          (Element) XMLTools.getRequiredNode((Node) nl.get(i), "./OnlineResource", nsContext);
      OnlineResource olr = parseOnLineResource(tmp);
      authorityURLs[i] = new AuthorityURL(name, olr.getLinkage().getHref());
    }

    LOG.exiting();
    return authorityURLs;
  }
  /**
   * Parse FeatureListURL
   *
   * @param layerElem
   * @return FeatureListURL[]
   * @throws XMLParsingException
   */
  protected FeatureListURL[] parseFeatureListURL(Element layerElem) throws XMLParsingException {
    LOG.entering();

    List nl = XMLTools.getNodes(layerElem, "./FeatureListURL", nsContext);
    FeatureListURL[] flURL = new FeatureListURL[nl.size()];
    for (int i = 0; i < flURL.length; i++) {

      String format = XMLTools.getRequiredNodeAsString((Node) nl.get(i), "./Format", nsContext);
      Element tmp =
          (Element) XMLTools.getRequiredNode((Node) nl.get(i), "./OnlineResource", nsContext);
      OnlineResource olr = parseOnLineResource(tmp);
      flURL[i] = new FeatureListURL(format, olr.getLinkage().getHref());
    }

    LOG.exiting();
    return flURL;
  }
  /**
   * Parse MetadataURL
   *
   * @param layerElem
   * @return MetadataURL[]
   * @throws XMLParsingException
   */
  protected MetadataURL[] parseMetadataURLs(Element layerElem) throws XMLParsingException {
    LOG.entering();

    List nl = XMLTools.getNodes(layerElem, "./MetadataURL", nsContext);
    MetadataURL[] metadataURL = new MetadataURL[nl.size()];
    for (int i = 0; i < metadataURL.length; i++) {
      String type = XMLTools.getRequiredNodeAsString((Node) nl.get(i), "./@type", nsContext);
      String format = XMLTools.getRequiredNodeAsString((Node) nl.get(i), "./Format", nsContext);
      Element tmp =
          (Element) XMLTools.getRequiredNode((Node) nl.get(i), "./OnlineResource", nsContext);
      OnlineResource olr = parseOnLineResource(tmp);
      metadataURL[i] = new MetadataURL(type, format, olr.getLinkage().getHref());
    }

    LOG.exiting();
    return metadataURL;
  }
  /**
   * Parse Legend URL
   *
   * @param node
   * @return LegendURL[]
   * @throws XMLParsingException
   */
  protected LegendURL[] parseLegendURL(Node node) throws XMLParsingException {
    LOG.entering();

    List nl = XMLTools.getNodes(node, "./LegendURL", nsContext);
    LegendURL[] lURL = new LegendURL[nl.size()];
    for (int i = 0; i < lURL.length; i++) {
      int width = XMLTools.getRequiredNodeAsInt((Node) nl.get(i), "./@width", nsContext);
      int height = XMLTools.getRequiredNodeAsInt((Node) nl.get(i), "./@height", nsContext);
      String format = XMLTools.getRequiredNodeAsString((Node) nl.get(i), "./Format", nsContext);
      Element tmp =
          (Element) XMLTools.getRequiredNode((Node) nl.get(i), "./OnlineResource", nsContext);
      OnlineResource olr = parseOnLineResource(tmp);
      lURL[i] = new LegendURL(width, height, format, olr.getLinkage().getHref());
    }

    LOG.exiting();
    return lURL;
  }
  /**
   * returns the services capabilitiy read from the WMPS capabilities file
   *
   * @return OperationsMetadata
   * @throws XMLParsingException
   */
  protected OperationsMetadata parseOperationsMetadata() throws XMLParsingException {
    LOG.entering();

    LOG.logDebug("Parsing operations metdata parameter.");
    Node opNode =
        XMLTools.getNode(getRootElement(), "./Capability/Request/GetCapabilities", nsContext);

    Operation getCapabilities = parseOperation(opNode);
    LOG.logDebug("Operation getCapabilities created for the GetCapabilities node.");

    opNode = XMLTools.getRequiredNode(getRootElement(), "./Capability/Request/PrintMap", nsContext);

    Operation printMap = parseOperation(opNode);

    LOG.logDebug("Operation printMap created for the PrintMap node.");

    WMPSOperationsMetadata metadata = new WMPSOperationsMetadata(getCapabilities, printMap);

    LOG.exiting();
    return metadata;
  }
  /**
   * Creates a <code>DCPType</code> object from the passed <code>DCP</code> element.
   * <p>
   * NOTE: Currently the <code>OnlineResources</code> included in the <code>DCPType</code> are
   * just stored as simple <code>URLs</code> (not as <code>OnLineResource</code> instances)!
   * <p>
   * NOTE: In an <code>OGCStandardCapabilitiesDocument</code> the <code>XLinks</code> (the
   * <code>URLs</code>) are stored in separate elements (<code>OnlineResource</code>), in
   * an <code>OGCCommonCapabilitiesDocument</code> they are the
   * <code>Get<code>/<code>Post</code> elements themselves.
   *
   * @param element
   *
   * @return created <code>DCPType</code>
   * @throws XMLParsingException
   *
   * @see org.deegree.ogcwebservices.getcapabilities.OGCStandardCapabilities
   */
  @Override
  protected DCPType getDCP(Element element) throws XMLParsingException {
    LOG.entering();
    DCPType dcpType = null;
    try {
      Element elem = (Element) XMLTools.getRequiredNode(element, "HTTP", nsContext);
      List nl = XMLTools.getNodes(elem, "Get", nsContext);

      URL[] get = new URL[nl.size()];
      for (int i = 0; i < get.length; i++) {
        String s = XMLTools.getNodeAsString((Node) nl.get(i), "./@xlink:href", nsContext, null);
        if (s == null) {
          s =
              XMLTools.getRequiredNodeAsString(
                  (Node) nl.get(i), "./OnlineResource/@xlink:href", nsContext);
        }
        get[i] = new URL(s);
      }
      nl = XMLTools.getNodes(elem, "Post", nsContext);

      URL[] post = new URL[nl.size()];
      for (int i = 0; i < post.length; i++) {
        String s = XMLTools.getNodeAsString((Node) nl.get(i), "./@xlink:href", nsContext, null);
        if (s == null) {
          s =
              XMLTools.getRequiredNodeAsString(
                  (Node) nl.get(i), "./OnlineResource/@xlink:href", nsContext);
        }
        post[i] = new URL(s);
      }
      Protocol protocol = new HTTP(get, post);
      dcpType = new DCPType(protocol);
    } catch (MalformedURLException e) {
      throw new XMLParsingException(
          "Couldn't parse DCPType onlineresource URL about: " + StringTools.stackTraceToString(e));
    }
    LOG.exiting();
    return dcpType;
  }
  /**
   * Creates a class representation of the document.
   *
   * @return OGCCapabilities class representation of the configuration document
   * @throws InvalidCapabilitiesException
   */
  @Override
  public OGCCapabilities parseCapabilities() throws InvalidCapabilitiesException {
    LOG.entering();

    LOG.logDebug("Parsing Capabilties Request.");
    ServiceIdentification serviceIdentification = null;
    ServiceProvider serviceProvider = null;
    UserDefinedSymbolization uds = null;
    OperationsMetadata metadata = null;
    Layer layer = null;
    String version = parseVersion();
    try {
      serviceIdentification = parseServiceIdentification();
      serviceProvider = parseServiceProvider();
      LOG.logDebug(
          "Retrieved serviceIdentification and serviceProvider information " + "from the request.");
      metadata = parseOperationsMetadata();
      LOG.logDebug("Retrieved metadData information from the request.");
      uds = parseUserDefinedSymbolization();
      Element layerElem =
          (Element) XMLTools.getRequiredNode(getRootElement(), "./Capability/Layer", nsContext);
      LOG.logDebug("Layer Element retrieved.");
      layer = parseLayers(layerElem, null);
    } catch (XMLParsingException e) {
      String msg =
          "Error parsing the capabilities request to retrieve 'serviceIdentification',"
              + " 'serviceProvider', 'metaData' and 'layer' "
              + e.getMessage();
      throw new InvalidCapabilitiesException(msg);
    } catch (UnknownCRSException e) {
      throw new InvalidCapabilitiesException(getClass().getName(), e.getMessage());
    }
    WMPSCapabilities wmpsCapabilities =
        new WMPSCapabilities(version, serviceIdentification, serviceProvider, uds, metadata, layer);
    LOG.exiting();
    return wmpsCapabilities;
  }