/**
   * Creates 'wsu:Id' attribute for wsu:Timestamp needed for signature.
   *
   * @param message
   * @return
   * @throws ParserException
   */
  private String createTimestampUuid(SoapMessage message) throws ParserException {

    NodeList timestampList =
        message
            .getHeader()
            .getOwnerDocument()
            .getElementsByTagNameNS(WSU_NAMESPACE, WSU_TIMESTAMP_LOCAL_NAME);

    assert timestampList.getLength() <= 1;

    if (timestampList.getLength() == 1) {
      assert timestampList.item(0).getNodeType() == Node.ELEMENT_NODE;

      Element timestamp = (Element) timestampList.item(0);
      String timestampId = Util.randomNCNameUUID();

      Attr wsuId = timestamp.getOwnerDocument().createAttributeNS(WSU_NAMESPACE, WSU_ID_LOCAL_NAME);
      wsuId.setPrefix(timestamp.getPrefix());

      wsuId.setValue(timestampId);
      timestamp.setAttributeNodeNS(wsuId);
      timestamp.setIdAttributeNode(wsuId, true);

      log.trace("Created wsu:Id for wsu:Timestamp: " + timestampId);

      return timestampId;
    }

    log.trace("Timestamp element not found in the message");

    return null;
  }
  /**
   * @param featureCollection
   * @param writer
   * @param fragment : true if we write in a stream, dont write start and end elements
   * @throws DataStoreException
   */
  public Element writeFeatureCollection(
      final FeatureCollection featureCollection, final boolean fragment, final boolean wfs)
      throws DataStoreException, ParserConfigurationException {

    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    // then we have to create document-loader:
    factory.setNamespaceAware(false);
    DocumentBuilder loader = factory.newDocumentBuilder();

    // creating a new DOM-document...
    Document document = loader.newDocument();

    // the XML header
    if (!fragment) {
      document.setXmlVersion("1.0");
      // writer.writeStartDocument("UTF-8", "1.0");
    }

    // the root Element
    final Element rootElement;
    if (wfs) {
      rootElement = document.createElementNS("http://www.opengis.net/wfs", "FeatureCollection");
      rootElement.setPrefix("wfs");
    } else {
      rootElement = document.createElementNS("http://www.opengis.net/gml", "FeatureCollection");
      rootElement.setPrefix("gml");
    }

    document.appendChild(rootElement);

    String collectionID = "";
    if (featureCollection.getID() != null) {
      collectionID = featureCollection.getID();
    }
    final Attr idAttribute = document.createAttributeNS(Namespaces.GML, "id");
    idAttribute.setValue(collectionID);
    idAttribute.setPrefix("gml");
    rootElement.setAttributeNodeNS(idAttribute);

    if (schemaLocation != null && !schemaLocation.equals("")) {
      rootElement.setAttributeNS(
          "http://www.w3.org/2001/XMLSchema-instance", "schemaLocation", schemaLocation);
    }

    /*FeatureType type = featureCollection.getFeatureType();
    if (type != null && type.getName() != null) {
        String namespace = type.getName().getNamespaceURI();
        if (namespace != null && !namespace.equals(Namespaces.GML)) {
            Prefix prefix    = getPrefix(namespace);
            writer.writeNamespace(prefix.prefix, namespace);
        }
    }*/
    /*
     * The boundedby part
     */
    final Element boundElement = writeBounds(featureCollection.getEnvelope(), document);
    if (boundElement != null) {
      rootElement.appendChild(boundElement);
    }

    // we write each feature member of the collection
    FeatureIterator iterator = featureCollection.iterator();
    try {
      while (iterator.hasNext()) {
        final Feature f = iterator.next();
        final Element memberElement = document.createElementNS(Namespaces.GML, "featureMember");
        memberElement.setPrefix("gml");
        memberElement.appendChild(writeFeature(f, document, true));
        rootElement.appendChild(memberElement);
      }

    } finally {
      // we close the stream
      iterator.close();
    }
    return rootElement;
  }
  /**
   * Write the feature into the stream.
   *
   * @param feature The feature
   * @param root
   * @throws XMLStreamException
   */
  public Element writeFeature(final Feature feature, final Document rootDocument, boolean fragment)
      throws ParserConfigurationException {

    final Document document;
    if (rootDocument == null) {
      DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
      // then we have to create document-loader:
      factory.setNamespaceAware(false);
      DocumentBuilder loader = factory.newDocumentBuilder();

      // creating a new DOM-document...
      document = loader.newDocument();
    } else {
      document = rootDocument;
    }

    // the root element of the xml document (type of the feature)
    final FeatureType type = feature.getType();
    final Name typeName = type.getName();
    final String namespace = typeName.getNamespaceURI();
    final String localPart = typeName.getLocalPart();

    final Element rootElement;
    final Prefix prefix;
    if (namespace != null) {
      prefix = getPrefix(namespace);
      rootElement = document.createElementNS(namespace, localPart);
      rootElement.setPrefix(prefix.prefix);

    } else {
      rootElement = document.createElement(localPart);
      prefix = null;
    }
    // if main document set the xmlns
    if (!fragment) {
      rootElement.setAttributeNS(
          "http://www.w3.org/2000/xmlns/", "xmlns:gml", "http://www.opengis.net/gml");
    }
    final Attr idAttr = document.createAttributeNS(Namespaces.GML, "id");
    idAttr.setValue(feature.getIdentifier().getID());
    idAttr.setPrefix("gml");
    rootElement.setAttributeNodeNS(idAttr);

    if (rootDocument == null) {
      document.appendChild(rootElement);
    }
    // write properties in the type order
    for (final PropertyDescriptor desc : type.getDescriptors()) {
      final Collection<Property> props = feature.getProperties(desc.getName());
      for (Property a : props) {
        final Object valueA = a.getValue();
        final PropertyType typeA = a.getType();
        final Name nameA = a.getName();
        final String nameProperty = nameA.getLocalPart();
        String namespaceProperty = nameA.getNamespaceURI();
        if (valueA instanceof Collection && !(typeA instanceof GeometryType)) {
          for (Object value : (Collection) valueA) {
            final Element element;
            if (namespaceProperty != null) {
              element = document.createElementNS(namespaceProperty, nameProperty);
            } else {
              element = document.createElement(nameProperty);
            }
            element.setTextContent(Utils.getStringValue(value));
            if (prefix != null) {
              element.setPrefix(prefix.prefix);
            }
            rootElement.appendChild(element);
          }

        } else if (valueA instanceof Map && !(typeA instanceof GeometryType)) {
          final Map<?, ?> map = (Map) valueA;
          for (Entry<?, ?> entry : map.entrySet()) {
            final Element element;
            if (namespaceProperty != null) {
              element = document.createElementNS(namespaceProperty, nameProperty);
            } else {
              element = document.createElement(nameProperty);
            }
            final Object key = entry.getKey();
            if (key != null) {
              element.setAttribute("name", (String) key);
            }
            element.setTextContent(Utils.getStringValue(entry.getValue()));
            if (prefix != null) {
              element.setPrefix(prefix.prefix);
            }
            rootElement.appendChild(element);
          }

        } else if (!(typeA instanceof GeometryType)) {
          String value = Utils.getStringValue(valueA);
          if (value != null || (value == null && !a.isNillable())) {

            if ((nameProperty.equals("name") || nameProperty.equals("description"))
                && !Namespaces.GML.equals(namespaceProperty)) {
              namespaceProperty = Namespaces.GML;
              LOGGER.warning(
                  "the property name and description of a feature must have the GML namespace");
            }
            final Element element;
            if (namespaceProperty != null) {
              element = document.createElementNS(namespaceProperty, nameProperty);
            } else {
              element = document.createElement(nameProperty);
            }
            if (value != null) {
              element.setTextContent(value);
            }
            if (prefix != null) {
              element.setPrefix(prefix.prefix);
            }
            rootElement.appendChild(element);
          }

          // we add the geometry
        } else {

          if (valueA != null) {
            final Element element;
            if (namespaceProperty != null) {
              element = document.createElementNS(namespaceProperty, nameProperty);
            } else {
              element = document.createElement(nameProperty);
            }
            if (prefix != null) {
              element.setPrefix(prefix.prefix);
            }
            Geometry isoGeometry =
                JTSUtils.toISO(
                    (com.vividsolutions.jts.geom.Geometry) valueA,
                    type.getCoordinateReferenceSystem());
            Marshaller marshaller = null;
            try {
              marshaller = POOL.acquireMarshaller();
              marshaller.setProperty(Marshaller.JAXB_FRAGMENT, true);
              marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, false);
              marshaller.marshal(OBJECT_FACTORY.buildAnyGeometry(isoGeometry), element);
            } catch (JAXBException ex) {
              LOGGER.log(
                  Level.WARNING,
                  "JAXB Exception while marshalling the iso geometry: " + ex.getMessage(),
                  ex);
            } finally {
              if (marshaller != null) {
                POOL.release(marshaller);
              }
            }
            rootElement.appendChild(element);
          }
        }
      }
    }

    // writer.writeEndElement();
    return rootElement;
  }