]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.util/src/org/argeo/util/dav/MultiStatusReader.java
Remove UI dependencies to JCR.
[lgpl/argeo-commons.git] / org.argeo.util / src / org / argeo / util / dav / MultiStatusReader.java
1 package org.argeo.util.dav;
2
3 import java.io.InputStream;
4 import java.util.Iterator;
5 import java.util.concurrent.ArrayBlockingQueue;
6 import java.util.concurrent.BlockingQueue;
7 import java.util.concurrent.CompletableFuture;
8 import java.util.concurrent.ExecutionException;
9 import java.util.concurrent.ForkJoinPool;
10 import java.util.concurrent.atomic.AtomicBoolean;
11
12 import javax.xml.namespace.QName;
13 import javax.xml.stream.FactoryConfigurationError;
14 import javax.xml.stream.XMLInputFactory;
15 import javax.xml.stream.XMLStreamConstants;
16 import javax.xml.stream.XMLStreamException;
17 import javax.xml.stream.XMLStreamReader;
18
19 class MultiStatusReader implements Iterator<DavResponse> {
20 private CompletableFuture<Boolean> empty = new CompletableFuture<Boolean>();
21 private AtomicBoolean processed = new AtomicBoolean(false);
22
23 private BlockingQueue<DavResponse> queue = new ArrayBlockingQueue<>(64);
24
25 private final String ignoredHref;
26
27 public MultiStatusReader(InputStream in) {
28 this(in, null);
29 }
30
31 /** Typically ignoring self */
32 public MultiStatusReader(InputStream in, String ignoredHref) {
33 this.ignoredHref = ignoredHref;
34 ForkJoinPool.commonPool().execute(() -> process(in));
35
36 }
37
38 protected void process(InputStream in) {
39 try {
40 XMLInputFactory inputFactory = XMLInputFactory.newFactory();
41 XMLStreamReader reader = inputFactory.createXMLStreamReader(in);
42
43 DavResponse currentResponse = null;
44 boolean collectiongProperties = false;
45
46 final QName COLLECTION = DavXmlElement.collection.qName(); // optimisation
47 elements: while (reader.hasNext()) {
48 reader.next();
49 if (reader.isStartElement()) {
50 QName name = reader.getName();
51 // System.out.println(name);
52 DavXmlElement davXmlElement = DavXmlElement.toEnum(name);
53 if (davXmlElement != null) {
54 switch (davXmlElement) {
55 case response:
56 currentResponse = new DavResponse();
57 break;
58 case href:
59 assert currentResponse != null;
60 while (reader.hasNext() && !reader.hasText())
61 reader.next();
62 String href = reader.getText();
63 currentResponse.setHref(href);
64 break;
65 // case collection:
66 // currentResponse.setCollection(true);
67 // break;
68 case prop:
69 collectiongProperties = true;
70 break;
71 case resourcetype:
72 while (reader.hasNext()) {
73 int event = reader.nextTag();
74 QName resourceType = reader.getName();
75 if (event == XMLStreamConstants.END_ELEMENT && name.equals(resourceType))
76 break;
77 assert currentResponse != null;
78 if (event == XMLStreamConstants.START_ELEMENT) {
79 if (COLLECTION.equals(resourceType))
80 currentResponse.setCollection(true);
81 else
82 currentResponse.getResourceTypes().add(resourceType);
83 }
84 }
85 break;
86 default:
87 // ignore
88 }
89 } else {
90 if (collectiongProperties) {
91 String value = null;
92 // TODO deal with complex properties
93 readProperty: while (reader.hasNext()) {
94 reader.next();
95 if (reader.getEventType() == XMLStreamConstants.END_ELEMENT)
96 break readProperty;
97 if (reader.getEventType() == XMLStreamConstants.CHARACTERS)
98 value = reader.getText();
99 }
100
101 if (name.getNamespaceURI().equals(DavResponse.MODE_DAV_NAMESPACE))
102 continue elements; // skip mod_dav properties
103
104 assert currentResponse != null;
105 currentResponse.getPropertyNames().add(name);
106 if (value != null)
107 currentResponse.getProperties().put(name, value);
108
109 }
110 }
111 } else if (reader.isEndElement()) {
112 QName name = reader.getName();
113 // System.out.println(name);
114 DavXmlElement davXmlElement = DavXmlElement.toEnum(name);
115 if (davXmlElement != null)
116 switch (davXmlElement) {
117 case response:
118 assert currentResponse != null;
119 if (ignoredHref == null || !ignoredHref.equals(currentResponse.getHref())) {
120 if (!empty.isDone())
121 empty.complete(false);
122 publish(currentResponse);
123 }
124 case prop:
125 collectiongProperties = false;
126 break;
127 default:
128 // ignore
129 }
130 }
131 }
132
133 if (!empty.isDone())
134 empty.complete(true);
135 } catch (FactoryConfigurationError | XMLStreamException e) {
136 throw new IllegalStateException("Cannot process DAV response", e);
137 } finally {
138 processed();
139 }
140 }
141
142 protected synchronized void publish(DavResponse response) {
143 try {
144 queue.put(response);
145 } catch (InterruptedException e) {
146 throw new IllegalStateException("Cannot put response " + response, e);
147 } finally {
148 notifyAll();
149 }
150 }
151
152 protected synchronized void processed() {
153 processed.set(true);
154 notifyAll();
155 }
156
157 @Override
158 public synchronized boolean hasNext() {
159 try {
160 if (empty.get())
161 return false;
162 while (!processed.get() && queue.isEmpty()) {
163 wait();
164 }
165 if (!queue.isEmpty())
166 return true;
167 if (processed.get())
168 return false;
169 throw new IllegalStateException("Cannot determine hasNext");
170 } catch (InterruptedException | ExecutionException e) {
171 throw new IllegalStateException("Cannot determine hasNext", e);
172 } finally {
173 notifyAll();
174 }
175 }
176
177 @Override
178 public synchronized DavResponse next() {
179 try {
180 if (!hasNext())
181 throw new IllegalStateException("No fursther items are available");
182
183 DavResponse response = queue.take();
184 return response;
185 } catch (InterruptedException e) {
186 throw new IllegalStateException("Cannot get next", e);
187 } finally {
188 notifyAll();
189 }
190 }
191
192 }