]> git.argeo.org Git - lgpl/argeo-commons.git/blobdiff - org.argeo.cms/src/org/argeo/cms/dav/MultiStatusWriter.java
First WebDav PROPFIND implementation server-side
[lgpl/argeo-commons.git] / org.argeo.cms / src / org / argeo / cms / dav / MultiStatusWriter.java
diff --git a/org.argeo.cms/src/org/argeo/cms/dav/MultiStatusWriter.java b/org.argeo.cms/src/org/argeo/cms/dav/MultiStatusWriter.java
new file mode 100644 (file)
index 0000000..45fcea0
--- /dev/null
@@ -0,0 +1,143 @@
+package org.argeo.cms.dav;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.CompletionStage;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.Consumer;
+
+import javax.xml.XMLConstants;
+import javax.xml.namespace.NamespaceContext;
+import javax.xml.namespace.QName;
+import javax.xml.stream.FactoryConfigurationError;
+import javax.xml.stream.XMLOutputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+
+public class MultiStatusWriter implements Consumer<DavResponse> {
+       private BlockingQueue<DavResponse> queue = new ArrayBlockingQueue<>(64);
+
+//     private OutputStream out;
+
+       private Thread processingThread;
+
+       private AtomicBoolean done = new AtomicBoolean(false);
+
+       private AtomicBoolean polling = new AtomicBoolean();
+
+       public void process(NamespaceContext namespaceContext, OutputStream out, CompletionStage<Void> published,
+                       boolean propname) throws IOException {
+               published.thenRun(() -> allPublished());
+               processingThread = Thread.currentThread();
+//             this.out = out;
+
+               try {
+                       XMLOutputFactory xmlOutputFactory = XMLOutputFactory.newFactory();
+                       XMLStreamWriter xsWriter = xmlOutputFactory.createXMLStreamWriter(out, StandardCharsets.UTF_8.name());
+                       xsWriter.setNamespaceContext(namespaceContext);
+                       xsWriter.setDefaultNamespace(DavXmlElement.WEBDAV_NAMESPACE_URI);
+
+                       xsWriter.writeStartDocument();
+                       DavXmlElement.multistatus.startElement(xsWriter);
+                       xsWriter.writeDefaultNamespace(DavXmlElement.WEBDAV_NAMESPACE_URI);
+
+                       poll: while (!(done.get() && queue.isEmpty())) {
+                               DavResponse davResponse;
+                               try {
+                                       polling.set(true);
+                                       davResponse = queue.poll(10, TimeUnit.MILLISECONDS);
+                                       if (davResponse == null)
+                                               continue poll;
+                                       System.err.println(davResponse.getHref());
+                               } catch (InterruptedException e) {
+                                       System.err.println(e);
+                                       continue poll;
+                               } finally {
+                                       polling.set(false);
+                               }
+
+                               writeDavResponse(xsWriter, davResponse, propname);
+                       }
+
+                       xsWriter.writeEndElement();// multistatus
+                       xsWriter.writeEndDocument();
+                       xsWriter.close();
+                       out.close();
+               } catch (FactoryConfigurationError | XMLStreamException e) {
+                       synchronized (this) {
+                               processingThread = null;
+                       }
+               }
+       }
+
+       protected void writeDavResponse(XMLStreamWriter xsWriter, DavResponse davResponse, boolean propname)
+                       throws XMLStreamException {
+               Set<String> namespaces = new HashSet<>();
+               for (QName key : davResponse.getPropertyNames()) {
+                       if (key.getNamespaceURI().equals(DavXmlElement.WEBDAV_NAMESPACE_URI))
+                               continue; // skip
+                       if (key.getNamespaceURI().equals(XMLConstants.W3C_XML_SCHEMA_NS_URI))
+                               continue; // skip
+                       namespaces.add(key.getNamespaceURI());
+               }
+               DavXmlElement.response.startElement(xsWriter);
+               // namespaces
+               for (String ns : namespaces)
+                       xsWriter.writeNamespace(xsWriter.getNamespaceContext().getPrefix(ns), ns);
+
+               DavXmlElement.href.setSimpleValue(xsWriter, davResponse.getHref());
+
+               {
+                       DavXmlElement.propstat.startElement(xsWriter);
+                       {
+                               DavXmlElement.prop.startElement(xsWriter);
+                               if (!davResponse.getResourceTypes().isEmpty() || davResponse.isCollection()) {
+                                       DavXmlElement.resourcetype.startElement(xsWriter);
+                                       if (davResponse.isCollection())
+                                               DavXmlElement.collection.emptyElement(xsWriter);
+                                       for (QName resourceType : davResponse.getResourceTypes()) {
+                                               xsWriter.writeEmptyElement(resourceType.getNamespaceURI(), resourceType.getLocalPart());
+                                       }
+                                       xsWriter.writeEndElement();// resource type
+                               }
+                               for (QName key : davResponse.getPropertyNames()) {
+                                       if (propname) {
+                                               xsWriter.writeEmptyElement(key.getNamespaceURI(), key.getLocalPart());
+                                       } else {
+                                               xsWriter.writeStartElement(key.getNamespaceURI(), key.getLocalPart());
+                                               xsWriter.writeCData(davResponse.getProperties().get(key));
+                                               xsWriter.writeEndElement();
+                                       }
+                               }
+                               xsWriter.writeEndElement();// prop
+                       }
+                       xsWriter.writeEndElement();// propstat
+               }
+               xsWriter.writeEndElement();// response
+       }
+
+       @Override
+       public void accept(DavResponse davResponse) {
+               try {
+                       queue.put(davResponse);
+               } catch (InterruptedException e) {
+                       e.printStackTrace();
+               }
+       }
+
+       protected synchronized void allPublished() {
+               done.set(true);
+               if (processingThread != null && queue.isEmpty() && polling.get()) {
+                       // we only interrupt if the queue is already processed
+                       // so as not to interrupt I/O
+                       processingThread.interrupt();
+               }
+       }
+
+}