1 package org
.argeo
.cms
.dav
;
3 import java
.io
.InputStream
;
4 import java
.nio
.charset
.StandardCharsets
;
5 import java
.util
.HashSet
;
6 import java
.util
.Iterator
;
8 import java
.util
.concurrent
.ArrayBlockingQueue
;
9 import java
.util
.concurrent
.BlockingQueue
;
10 import java
.util
.concurrent
.CompletableFuture
;
11 import java
.util
.concurrent
.ExecutionException
;
12 import java
.util
.concurrent
.ForkJoinPool
;
13 import java
.util
.concurrent
.atomic
.AtomicBoolean
;
15 import javax
.xml
.namespace
.QName
;
16 import javax
.xml
.stream
.FactoryConfigurationError
;
17 import javax
.xml
.stream
.XMLInputFactory
;
18 import javax
.xml
.stream
.XMLStreamConstants
;
19 import javax
.xml
.stream
.XMLStreamException
;
20 import javax
.xml
.stream
.XMLStreamReader
;
22 import org
.argeo
.cms
.http
.HttpStatus
;
25 * Asynchronously iterate over the response statuses of the response to a
28 class MultiStatusReader
implements Iterator
<DavResponse
> {
29 private CompletableFuture
<Boolean
> empty
= new CompletableFuture
<Boolean
>();
30 private AtomicBoolean processed
= new AtomicBoolean(false);
32 private BlockingQueue
<DavResponse
> queue
= new ArrayBlockingQueue
<>(64);
34 private final String ignoredHref
;
36 public MultiStatusReader(InputStream in
) {
40 /** Typically ignoring self */
41 public MultiStatusReader(InputStream in
, String ignoredHref
) {
42 this.ignoredHref
= ignoredHref
;
43 ForkJoinPool
.commonPool().execute(() -> process(in
));
46 protected void process(InputStream in
) {
48 XMLInputFactory inputFactory
= XMLInputFactory
.newFactory();
49 XMLStreamReader reader
= inputFactory
.createXMLStreamReader(in
, StandardCharsets
.UTF_8
.name());
51 DavResponse currentResponse
= null;
52 boolean collectiongProperties
= false;
53 Set
<QName
> currentPropertyNames
= null;
54 HttpStatus currentStatus
= null;
56 final QName COLLECTION
= DavXmlElement
.collection
.qName(); // optimisation
57 elements
: while (reader
.hasNext()) {
59 if (reader
.isStartElement()) {
60 QName name
= reader
.getName();
61 // System.out.println(name);
62 DavXmlElement davXmlElement
= DavXmlElement
.toEnum(name
);
63 if (davXmlElement
!= null) {
64 switch (davXmlElement
) {
66 currentResponse
= new DavResponse();
69 assert currentResponse
!= null;
70 while (reader
.hasNext() && !reader
.hasText())
72 String href
= reader
.getText();
73 currentResponse
.setHref(href
);
76 // currentResponse.setCollection(true);
80 String statusLine
= reader
.getText();
81 currentStatus
= HttpStatus
.parseStatusLine(statusLine
);
84 collectiongProperties
= true;
85 currentPropertyNames
= new HashSet
<>();
88 while (reader
.hasNext()) {
89 int event
= reader
.nextTag();
90 QName resourceType
= reader
.getName();
91 if (event
== XMLStreamConstants
.END_ELEMENT
&& name
.equals(resourceType
))
93 assert currentResponse
!= null;
94 if (event
== XMLStreamConstants
.START_ELEMENT
) {
95 if (COLLECTION
.equals(resourceType
))
96 currentResponse
.setCollection(true);
98 currentResponse
.getResourceTypes().add(resourceType
);
106 if (collectiongProperties
) {
108 // TODO deal with complex properties
109 readProperty
: while (reader
.hasNext()) {
111 if (reader
.getEventType() == XMLStreamConstants
.END_ELEMENT
)
113 if (reader
.getEventType() == XMLStreamConstants
.CHARACTERS
)
114 value
= reader
.getText();
117 if (name
.getNamespaceURI().equals(DavResponse
.MOD_DAV_NAMESPACE
))
118 continue elements
; // skip mod_dav properties
120 assert currentResponse
!= null;
121 currentPropertyNames
.add(name
);
123 currentResponse
.getProperties().put(name
, value
);
127 } else if (reader
.isEndElement()) {
128 QName name
= reader
.getName();
129 // System.out.println(name);
130 DavXmlElement davXmlElement
= DavXmlElement
.toEnum(name
);
131 if (davXmlElement
!= null)
132 switch (davXmlElement
) {
134 currentResponse
.getPropertyNames(currentStatus
).addAll(currentPropertyNames
);
135 currentPropertyNames
= null;
138 assert currentResponse
!= null;
139 if (ignoredHref
== null || !ignoredHref
.equals(currentResponse
.getHref())) {
141 empty
.complete(false);
142 publish(currentResponse
);
145 collectiongProperties
= false;
154 empty
.complete(true);
155 } catch (FactoryConfigurationError
| XMLStreamException e
) {
156 empty
.completeExceptionally(e
);
157 throw new IllegalStateException("Cannot process DAV response", e
);
163 protected synchronized void publish(DavResponse response
) {
166 } catch (InterruptedException e
) {
167 throw new IllegalStateException("Cannot put response " + response
, e
);
173 protected synchronized void processed() {
179 public synchronized boolean hasNext() {
183 while (!processed
.get() && queue
.isEmpty()) {
186 if (!queue
.isEmpty())
190 throw new IllegalStateException("Cannot determine hasNext");
191 } catch (InterruptedException
| ExecutionException e
) {
192 throw new IllegalStateException("Cannot determine hasNext", e
);
199 public synchronized DavResponse
next() {
202 throw new IllegalStateException("No fursther items are available");
204 DavResponse response
= queue
.take();
206 } catch (InterruptedException e
) {
207 throw new IllegalStateException("Cannot get next", e
);