]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.cms/src/org/argeo/cms/dav/MultiStatusWriter.java
FS utils throws IOException
[lgpl/argeo-commons.git] / org.argeo.cms / src / org / argeo / cms / dav / MultiStatusWriter.java
1 package org.argeo.cms.dav;
2
3 import java.io.IOException;
4 import java.io.OutputStream;
5 import java.nio.charset.StandardCharsets;
6 import java.util.HashSet;
7 import java.util.Set;
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;
14
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;
22
23 import org.argeo.cms.http.HttpStatus;
24
25 class MultiStatusWriter implements Consumer<DavResponse> {
26 private BlockingQueue<DavResponse> queue = new ArrayBlockingQueue<>(64);
27
28 // private OutputStream out;
29
30 private Thread processingThread;
31
32 private AtomicBoolean done = new AtomicBoolean(false);
33
34 private AtomicBoolean polling = new AtomicBoolean();
35
36 private String protocol;
37
38 public MultiStatusWriter(String protocol) {
39 this.protocol = protocol;
40 }
41
42 public void process(NamespaceContext namespaceContext, OutputStream out, CompletionStage<Void> published,
43 boolean propname) throws IOException {
44 published.thenRun(() -> allPublished());
45 processingThread = Thread.currentThread();
46 // this.out = out;
47
48 try {
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);
53
54 xsWriter.writeStartDocument();
55 DavXmlElement.multistatus.startElement(xsWriter);
56 xsWriter.writeDefaultNamespace(DavXmlElement.WEBDAV_NAMESPACE_URI);
57
58 poll: while (!(done.get() && queue.isEmpty())) {
59 DavResponse davResponse;
60 try {
61 polling.set(true);
62 davResponse = queue.poll(10, TimeUnit.MILLISECONDS);
63 if (davResponse == null)
64 continue poll;
65 //System.err.println(davResponse.getHref());
66 } catch (InterruptedException e) {
67 //System.err.println(e);
68 continue poll;
69 } finally {
70 polling.set(false);
71 }
72
73 writeDavResponse(xsWriter, davResponse, propname);
74 }
75
76 xsWriter.writeEndElement();// multistatus
77 xsWriter.writeEndDocument();
78 xsWriter.close();
79 out.close();
80 } catch (FactoryConfigurationError | XMLStreamException e) {
81 synchronized (this) {
82 processingThread = null;
83 }
84 }
85 }
86
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))
93 continue; // skip
94 if (key.getNamespaceURI().equals(XMLConstants.W3C_XML_SCHEMA_NS_URI))
95 continue; // skip
96 namespaces.add(key.getNamespaceURI());
97 }
98 DavXmlElement.response.startElement(xsWriter);
99 // namespaces
100 for (String ns : namespaces)
101 xsWriter.writeNamespace(xsWriter.getNamespaceContext().getPrefix(ns), ns);
102
103 DavXmlElement.href.setSimpleValue(xsWriter, davResponse.getHref());
104
105 {
106 for (HttpStatus status : davResponse.getStatuses()) {
107 DavXmlElement.propstat.startElement(xsWriter);
108 {
109 DavXmlElement.prop.startElement(xsWriter);
110
111 // resourcetype
112 if (HttpStatus.OK.equals(status))
113 if (propname) {
114 DavXmlElement.resourcetype.emptyElement(xsWriter);
115 } else {
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());
123 }
124 xsWriter.writeEndElement();// resource type
125 }
126 }
127
128 properties: for (QName key : davResponse.getPropertyNames(status)) {
129 if (DavXmlElement.resourcetype.qName().equals(key))
130 continue properties;
131
132 if (propname) {
133 xsWriter.writeEmptyElement(key.getNamespaceURI(), key.getLocalPart());
134 } else {
135 xsWriter.writeStartElement(key.getNamespaceURI(), key.getLocalPart());
136 xsWriter.writeCData(davResponse.getProperties().get(key));
137 xsWriter.writeEndElement();
138 }
139 }
140 xsWriter.writeEndElement();// prop
141 }
142 DavXmlElement.status.setSimpleValue(xsWriter, status.getStatusLine(protocol));
143 xsWriter.writeEndElement();// propstat
144 }
145 }
146 xsWriter.writeEndElement();// response
147 }
148
149 @Override
150 public void accept(DavResponse davResponse) {
151 try {
152 queue.put(davResponse);
153 } catch (InterruptedException e) {
154 e.printStackTrace();
155 }
156 }
157
158 protected synchronized void allPublished() {
159 done.set(true);
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();
164 }
165 }
166
167 }