/**
  * Special handling for polymorphic mapping. Works out the polymorphic type name by evaluating the
  * function on the feature, then set the relevant sub-type values.
  *
  * @param target The target feature to be encoded
  * @param id The target feature id
  * @param nestedMapping The mapping that is polymorphic
  * @param source The source simple feature
  * @param xpath The xpath of polymorphic type
  * @param clientPropsMappings Client properties
  * @throws IOException
  */
 private Attribute setPolymorphicValues(
     Name mappingName,
     Attribute target,
     String id,
     NestedAttributeMapping nestedMapping,
     Object source,
     StepList xpath,
     Map<Name, Expression> clientPropsMappings)
     throws IOException {
   // process sub-type mapping
   DataAccess<FeatureType, Feature> da = DataAccessRegistry.getDataAccess((Name) mappingName);
   if (da instanceof AppSchemaDataAccess) {
     // why wouldn't it be? check just to be safe
     FeatureTypeMapping fTypeMapping =
         ((AppSchemaDataAccess) da).getMappingByName((Name) mappingName);
     List<AttributeMapping> polymorphicMappings = fTypeMapping.getAttributeMappings();
     AttributeDescriptor attDescriptor = fTypeMapping.getTargetFeature();
     AttributeType type = attDescriptor.getType();
     Name polymorphicTypeName = attDescriptor.getName();
     StepList prefixedXpath = xpath.clone();
     prefixedXpath.add(
         new Step(
             new QName(
                 polymorphicTypeName.getNamespaceURI(),
                 polymorphicTypeName.getLocalPart(),
                 this.namespaces.getPrefix(polymorphicTypeName.getNamespaceURI())),
             1));
     if (!fTypeMapping.getFeatureIdExpression().equals(Expression.NIL)) {
       id = fTypeMapping.getFeatureIdExpression().evaluate(source, String.class);
     }
     Attribute instance =
         xpathAttributeBuilder.set(
             target, prefixedXpath, null, id, type, false, attDescriptor, null);
     setClientProperties(instance, source, clientPropsMappings);
     for (AttributeMapping mapping : polymorphicMappings) {
       if (skipTopElement(polymorphicTypeName, mapping, type)) {
         // if the top level mapping for the Feature itself, the attribute instance
         // has already been created.. just need to set the client properties
         setClientProperties(instance, source, mapping.getClientProperties());
         continue;
       }
       setAttributeValue(
           instance, null, source, mapping, null, null, selectedProperties.get(mapping));
     }
     return instance;
   }
   return null;
 }
  public Element AbstractFeatureTypeEncode(
      Object object, Document document, Element value, XSDIdRegistry idSet) {
    Feature feature = (Feature) object;
    String id = feature.getIdentifier().getID();
    Name typeName;
    if (feature.getDescriptor() == null) {
      // no descriptor, assume WFS feature type name is the same as the name of the content
      // model type
      typeName = feature.getType().getName();
    } else {
      // honour the name set in the descriptor
      typeName = feature.getDescriptor().getName();
    }
    Element encoding =
        document.createElementNS(typeName.getNamespaceURI(), typeName.getLocalPart());
    if (!(feature instanceof SimpleFeature) && idSet != null) {
      if (idSet.idExists(id)) {
        // XSD type ids can only appear once in the same document, otherwise the document is
        // not schema valid. Attributes of the same ids should be encoded as xlink:href to
        // the existing attribute.
        encoding.setAttributeNS(XLINK.NAMESPACE, XLINK.HREF.getLocalPart(), "#" + id.toString());
        // make sure the attributes aren't encoded
        feature.setValue(Collections.emptyList());
        return encoding;
      } else {
        idSet.add(id);
      }
    }
    encoding.setAttributeNS(gml.getNamespaceURI(), "id", id);
    encodeClientProperties(feature, value);

    return encoding;
  }
 /**
  * Encode any client properties (XML attributes) found in the UserData map of a ComplexAttribute
  * as XML attributes of the element.
  *
  * @param complex the ComplexAttribute to search for client properties
  * @param element the element to which XML attributes should be added
  */
 @SuppressWarnings("unchecked")
 public static void encodeClientProperties(Property complex, Element element) {
   Map<Name, Object> clientProperties =
       (Map<Name, Object>) complex.getUserData().get(Attributes.class);
   if (clientProperties != null) {
     for (Name name : clientProperties.keySet()) {
       if (clientProperties.get(name) != null) {
         element.setAttributeNS(
             name.getNamespaceURI(), name.getLocalPart(), clientProperties.get(name).toString());
       }
     }
   }
 }
    /**
     * Handles the encoding of the layers elements.
     *
     * <p>This method does a search over the SRS of all the layers to see if there are at least a
     * common one, as needed by the spec: "<i>The root Layer element shall include a sequence of
     * zero or more &lt;SRS&gt; elements listing all SRSes that are common to all subsidiary layers.
     * Use a single SRS element with empty content (like so: "&lt;SRS&gt;&lt;/SRS&gt;") if there is
     * no common SRS."</i>
     *
     * <p>By the other hand, this search is also used to collecto the whole latlon bbox, as stated
     * by the spec: <i>"The bounding box metadata in Capabilities XML specify the minimum enclosing
     * rectangle for the layer as a whole."</i>
     *
     * @task TODO: manage this differently when we have the layer list of the WMS service decoupled
     *     from the feature types configured for the server instance. (This involves nested layers,
     *     gridcoverages, etc)
     */
    private void handleLayers() {
      start("Layer");

      final List<LayerInfo> layers;

      // filter the layers if a namespace filter has been set
      if (request.getNamespace() != null) {
        final List<LayerInfo> allLayers = wmsConfig.getLayers();
        layers = new ArrayList<LayerInfo>();

        String namespace = wmsConfig.getNamespaceByPrefix(request.getNamespace());
        for (LayerInfo layer : allLayers) {
          Name name = layer.getResource().getQualifiedName();
          if (name.getNamespaceURI().equals(namespace)) {
            layers.add(layer);
          }
        }
      } else {
        layers = wmsConfig.getLayers();
      }

      WMSInfo serviceInfo = wmsConfig.getServiceInfo();
      element("Title", serviceInfo.getTitle());
      element("Abstract", serviceInfo.getAbstract());

      List<String> srsList = serviceInfo.getSRS();
      Set<String> srs = new HashSet<String>();
      if (srsList != null) {
        srs.addAll(srsList);
      }
      handleRootCrsList(srs);

      handleRootBbox(layers);

      // now encode each layer individually
      LayerTree featuresLayerTree = new LayerTree(layers);
      handleLayerTree(featuresLayerTree);

      try {
        List<LayerGroupInfo> layerGroups = wmsConfig.getLayerGroups();
        handleLayerGroups(new ArrayList<LayerGroupInfo>(layerGroups));
      } catch (FactoryException e) {
        throw new RuntimeException("Can't obtain Envelope of Layer-Groups: " + e.getMessage(), e);
      } catch (TransformException e) {
        throw new RuntimeException("Can't obtain Envelope of Layer-Groups: " + e.getMessage(), e);
      }

      end("Layer");
    }
 /** @return the tree of feature references for this type */
 public RevTree getCurrentVersion() {
   // assume HEAD is at MASTER
   try {
     final Name typeName = this.type.getName();
     GeoGIT geogit = dataStore.getGeogit();
     RevTree typeTree =
         geogit
             .getRepository()
             .getWorkingTree()
             .getHeadVersion(new QName(typeName.getNamespaceURI(), typeName.getLocalPart()));
     return typeTree;
   } catch (Exception e) {
     throw new RuntimeException(e);
   }
 }
  /**
   * 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;
  }
 /** Sets the local name and namespace uri of the built type. */
 public void setName(Name name) {
   setName(name.getLocalPart());
   setNamespaceURI(name.getNamespaceURI());
 }