1 package org
.argeo
.cms
.dav
;
3 import java
.io
.IOException
;
4 import java
.io
.OutputStream
;
5 import java
.nio
.charset
.StandardCharsets
;
6 import java
.util
.HashSet
;
8 import java
.util
.concurrent
.ArrayBlockingQueue
;
9 import java
.util
.concurrent
.BlockingQueue
;
10 import java
.util
.concurrent
.CompletionStage
;
11 import java
.util
.concurrent
.TimeUnit
;
12 import java
.util
.concurrent
.atomic
.AtomicBoolean
;
13 import java
.util
.function
.Consumer
;
15 import javax
.xml
.XMLConstants
;
16 import javax
.xml
.namespace
.NamespaceContext
;
17 import javax
.xml
.namespace
.QName
;
18 import javax
.xml
.stream
.FactoryConfigurationError
;
19 import javax
.xml
.stream
.XMLOutputFactory
;
20 import javax
.xml
.stream
.XMLStreamException
;
21 import javax
.xml
.stream
.XMLStreamWriter
;
23 import org
.argeo
.cms
.http
.HttpStatus
;
25 class MultiStatusWriter
implements Consumer
<DavResponse
> {
26 private BlockingQueue
<DavResponse
> queue
= new ArrayBlockingQueue
<>(64);
28 // private OutputStream out;
30 private Thread processingThread
;
32 private AtomicBoolean done
= new AtomicBoolean(false);
34 private AtomicBoolean polling
= new AtomicBoolean();
36 private String protocol
;
38 public MultiStatusWriter(String protocol
) {
39 this.protocol
= protocol
;
42 public void process(NamespaceContext namespaceContext
, OutputStream out
, CompletionStage
<Void
> published
,
43 boolean propname
) throws IOException
{
44 published
.thenRun(() -> allPublished());
45 processingThread
= Thread
.currentThread();
49 XMLOutputFactory xmlOutputFactory
= XMLOutputFactory
.newFactory();
50 XMLStreamWriter xsWriter
= xmlOutputFactory
.createXMLStreamWriter(out
, StandardCharsets
.UTF_8
.name());
51 xsWriter
.setNamespaceContext(namespaceContext
);
52 xsWriter
.setDefaultNamespace(DavXmlElement
.WEBDAV_NAMESPACE_URI
);
54 xsWriter
.writeStartDocument();
55 DavXmlElement
.multistatus
.startElement(xsWriter
);
56 xsWriter
.writeDefaultNamespace(DavXmlElement
.WEBDAV_NAMESPACE_URI
);
58 poll
: while (!(done
.get() && queue
.isEmpty())) {
59 DavResponse davResponse
;
62 davResponse
= queue
.poll(10, TimeUnit
.MILLISECONDS
);
63 if (davResponse
== null)
65 //System.err.println(davResponse.getHref());
66 } catch (InterruptedException e
) {
67 //System.err.println(e);
73 writeDavResponse(xsWriter
, davResponse
, propname
);
76 xsWriter
.writeEndElement();// multistatus
77 xsWriter
.writeEndDocument();
80 } catch (FactoryConfigurationError
| XMLStreamException e
) {
82 processingThread
= null;
87 protected void writeDavResponse(XMLStreamWriter xsWriter
, DavResponse davResponse
, boolean propname
)
88 throws XMLStreamException
{
89 Set
<String
> namespaces
= new HashSet
<>();
90 for (HttpStatus status
: davResponse
.getStatuses())
91 for (QName key
: davResponse
.getPropertyNames(status
)) {
92 if (key
.getNamespaceURI().equals(DavXmlElement
.WEBDAV_NAMESPACE_URI
))
94 if (key
.getNamespaceURI().equals(XMLConstants
.W3C_XML_SCHEMA_NS_URI
))
96 namespaces
.add(key
.getNamespaceURI());
98 DavXmlElement
.response
.startElement(xsWriter
);
100 for (String ns
: namespaces
)
101 xsWriter
.writeNamespace(xsWriter
.getNamespaceContext().getPrefix(ns
), ns
);
103 DavXmlElement
.href
.setSimpleValue(xsWriter
, davResponse
.getHref());
106 for (HttpStatus status
: davResponse
.getStatuses()) {
107 DavXmlElement
.propstat
.startElement(xsWriter
);
109 DavXmlElement
.prop
.startElement(xsWriter
);
112 if (HttpStatus
.OK
.equals(status
))
114 DavXmlElement
.resourcetype
.emptyElement(xsWriter
);
116 if (!davResponse
.getResourceTypes().isEmpty() || davResponse
.isCollection()) {
117 DavXmlElement
.resourcetype
.startElement(xsWriter
);
118 if (davResponse
.isCollection())
119 DavXmlElement
.collection
.emptyElement(xsWriter
);
120 for (QName resourceType
: davResponse
.getResourceTypes()) {
121 xsWriter
.writeEmptyElement(resourceType
.getNamespaceURI(),
122 resourceType
.getLocalPart());
124 xsWriter
.writeEndElement();// resource type
128 properties
: for (QName key
: davResponse
.getPropertyNames(status
)) {
129 if (DavXmlElement
.resourcetype
.qName().equals(key
))
133 xsWriter
.writeEmptyElement(key
.getNamespaceURI(), key
.getLocalPart());
135 xsWriter
.writeStartElement(key
.getNamespaceURI(), key
.getLocalPart());
136 xsWriter
.writeCData(davResponse
.getProperties().get(key
));
137 xsWriter
.writeEndElement();
140 xsWriter
.writeEndElement();// prop
142 DavXmlElement
.status
.setSimpleValue(xsWriter
, status
.getStatusLine(protocol
));
143 xsWriter
.writeEndElement();// propstat
146 xsWriter
.writeEndElement();// response
150 public void accept(DavResponse davResponse
) {
152 queue
.put(davResponse
);
153 } catch (InterruptedException e
) {
158 protected synchronized void allPublished() {
160 if (processingThread
!= null && queue
.isEmpty() && polling
.get()) {
161 // we only interrupt if the queue is already processed
162 // so as not to interrupt I/O
163 processingThread
.interrupt();