WfsTransactionRequest.java
package de.turnertech.ows.servlet;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import de.turnertech.ows.Logging;
import de.turnertech.ows.common.ExceptionCode;
import de.turnertech.ows.common.Model;
import de.turnertech.ows.common.ModelEncoder;
import de.turnertech.ows.common.ModelEncoderProvider;
import de.turnertech.ows.common.OwsContext;
import de.turnertech.ows.common.OwsRequestContext;
import de.turnertech.ows.common.RequestHandler;
import de.turnertech.ows.filter.OgcFilter;
import de.turnertech.ows.filter.OgcFilterDecoder;
import de.turnertech.ows.gml.FeatureDecoder;
import de.turnertech.ows.gml.FeatureType;
import de.turnertech.ows.gml.GmlDecoderContext;
import de.turnertech.ows.gml.IFeature;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
public class WfsTransactionRequest implements RequestHandler {
@Override
public void handleRequest(HttpServletRequest request, HttpServletResponse response, OwsContext owsContext, OwsRequestContext requestContext) throws ServletException, IOException {
response.setContentType(RequestHandler.CONTENT_XML);
Set<Model> modelsToSave = new HashSet<>();
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
factory.setIgnoringElementContentWhitespace(true);
factory.setIgnoringComments(true);
try {
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(request.getInputStream());
Element root = document.getDocumentElement();
root.normalize();
NodeList deleteEntries = root.getElementsByTagName("Delete");
NodeList insertEntries = root.getElementsByTagName("Insert");
for(int i = 0; i < deleteEntries.getLength(); ++i) {
Logging.LOG.fine("Transaction - Delete");
// Delete entries have one child element, and one attribute. There is no need to cast to Element here
// 15.3.4
Node deleteEntry = deleteEntries.item(i);
if(deleteEntry == null) {
Logging.LOG.severe("Something went wrong getting the Delete elements from a transaction");
response.sendError(400, ErrorServlet.encodeMessage(ExceptionCode.OPERATION_PARSING_FAILED.toString(), "Delete", "Something went wrong decoding the Delete entry"));
return;
}
NodeList filterNodeList = ((Element)deleteEntry).getElementsByTagName("Filter");
if(filterNodeList == null || filterNodeList.getLength() == 0) {
Logging.LOG.severe("Something went wrong getting the Filter element from a Delete Transaction");
response.sendError(400, ErrorServlet.encodeMessage(ExceptionCode.OPERATION_PARSING_FAILED.toString(), "Filter", "Could not locate the Filter element for a Delete operation"));
return;
}
Node filter = filterNodeList.item(0);
Node typeNameNode = deleteEntry.getAttributes().getNamedItem("typeName");
if(typeNameNode == null) {
Logging.LOG.severe("Something went wrong getting the typeName attribute from a Filter");
response.sendError(400, ErrorServlet.encodeMessage(ExceptionCode.OPERATION_PARSING_FAILED.toString(), "typeName", "Could not locate the typeName element for a Filter operation"));
return;
}
String prefix = null;
String typeName = typeNameNode.getNodeValue();
if(typeName.contains(":")) {
String[] parts = typeName.split(":", 2);
prefix = parts[0];
typeName = parts[1];
}
String namespaceUri = root.getAttribute("xmlns:" + prefix);
if(namespaceUri == null || "".equals(namespaceUri)) {
Node nsElement = deleteEntry.getAttributes().getNamedItem("xmlns:" + prefix);
namespaceUri = nsElement == null ? null : nsElement.getTextContent();
}
if(namespaceUri == null || "".equals(namespaceUri)) {
Logging.LOG.severe("Something went wrong getting the typeName xmlns attribute from a Filter");
response.sendError(400, ErrorServlet.encodeMessage(ExceptionCode.OPERATION_PARSING_FAILED.toString(), "typeName", "Could not locate the typeName xmlns element for a Filter operation"));
return;
}
OgcFilter ogcFilter = OgcFilterDecoder.getFilter(filter);
FeatureType featureType = owsContext.getWfsCapabilities().getFeatureType(namespaceUri, typeName);
Model model = owsContext.getModelProvider().getModel(featureType);
Collection<IFeature> featuresToRemove = model.filter(ogcFilter);
model.removeAll(featuresToRemove);
modelsToSave.add(model);
}
for(int i = 0; i < insertEntries.getLength(); ++i) {
Logging.LOG.fine("Transaction - Insert");
Element insertEntry = insertEntries.item(i) instanceof Element ? (Element)insertEntries.item(i) : null;
if(insertEntry == null) {
Logging.LOG.severe("Something went wrong getting the Insert elements from a transaction");
continue;
}
NodeList individualFeatureEntries = insertEntry.getChildNodes();
for(int j = 0; j < individualFeatureEntries.getLength(); ++j) {
Node featureEntry = individualFeatureEntries.item(j);
if(featureEntry.getNodeType() == Node.ELEMENT_NODE) {
String prefix = featureEntry.getPrefix();
String namespaceUri = featureEntry.getNamespaceURI();
String name = featureEntry.getNodeName();
if(namespaceUri == null && prefix == null && name.contains(":")) {
String[] parts = name.split(":", 2);
prefix = parts[0];
name = parts[1];
}
if(namespaceUri == null && prefix != null) {
namespaceUri = document.lookupNamespaceURI(prefix);
}
if(namespaceUri == null && prefix != null) {
namespaceUri = root.getAttribute("xmlns:" + prefix);
namespaceUri = "".equals(namespaceUri) ? null : namespaceUri;
}
if(namespaceUri == null) {
Node localXmlnsNode = featureEntry.getAttributes().getNamedItem("xmlns");
namespaceUri = localXmlnsNode == null ? null : localXmlnsNode.getTextContent();
}
if(namespaceUri == null) {
response.sendError(400, ErrorServlet.encodeMessage(ExceptionCode.OPERATION_PARSING_FAILED.toString(), "xmlns", "No xmlns supplied for: " + featureEntry.getNodeName()));
return;
}
FeatureType featureType = owsContext.getWfsCapabilities().getFeatureType(namespaceUri, name);
if(featureType == null) {
response.sendError(400, ErrorServlet.encodeMessage(ExceptionCode.OPERATION_PARSING_FAILED.toString(), "Insert", "Feature Type not supported: " + name));
return;
}
Model model = owsContext.getModelProvider().getModel(featureType);
IFeature feature = FeatureDecoder.decode(featureEntry, new GmlDecoderContext(), featureType);
model.add(feature);
modelsToSave.add(model);
}
}
}
ModelEncoderProvider modelEncoderProvider = owsContext.getModelEncoderProvider();
ModelEncoder encoder = modelEncoderProvider.getModelEncoder(requestContext, ModelEncoderProvider.GML32);
for(Model model : modelsToSave) {
File saveFile = model.getStorageLocation();
try(FileOutputStream fout = new FileOutputStream(saveFile, false)) {
encoder.encode(model, fout, owsContext, requestContext);
} catch (Exception e) {
Logging.LOG.severe("Could not save changes! Potential data loss!");
response.sendError(500, ErrorServlet.encodeMessage(ExceptionCode.OPERATION_PARSING_FAILED.toString(), "transaction", "Could not save changes! Potential data loss!"));
return;
}
}
} catch (Exception e) {
Logging.LOG.severe("Could not decode GML from Transaction");
}
}
}