Refactor WebDav implementation
[lgpl/argeo-commons.git] / org.argeo.cms / src / org / argeo / cms / internal / runtime / CmsAcrHttpHandler.java
index 11fc1a3667140ea5b444947cd83dab98112f1642..5a42a3e383ec2d9435af424f7276f394e3f18623 100644 (file)
@@ -2,7 +2,6 @@ package org.argeo.cms.internal.runtime;
 
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.OutputStream;
 import java.util.Collection;
 import java.util.Map;
 import java.util.Optional;
@@ -14,76 +13,57 @@ import java.util.function.Consumer;
 import javax.xml.namespace.QName;
 
 import org.argeo.api.acr.Content;
+import org.argeo.api.acr.ContentNotFoundException;
 import org.argeo.api.acr.ContentSession;
 import org.argeo.api.acr.DName;
 import org.argeo.api.acr.spi.ProvidedRepository;
 import org.argeo.api.cms.CmsConstants;
-import org.argeo.cms.acr.ContentUtils;
 import org.argeo.cms.auth.RemoteAuthUtils;
 import org.argeo.cms.dav.DavDepth;
-import org.argeo.cms.dav.DavMethod;
+import org.argeo.cms.dav.DavHttpHandler;
 import org.argeo.cms.dav.DavPropfind;
 import org.argeo.cms.dav.DavResponse;
-import org.argeo.cms.dav.DavXmlElement;
-import org.argeo.cms.dav.MultiStatusWriter;
 import org.argeo.cms.internal.http.RemoteAuthHttpExchange;
 import org.argeo.util.StreamUtils;
-import org.argeo.util.http.HttpMethod;
 import org.argeo.util.http.HttpResponseStatus;
-import org.argeo.util.http.HttpServerUtils;
 
 import com.sun.net.httpserver.HttpExchange;
-import com.sun.net.httpserver.HttpHandler;
 
-public class CmsAcrHttpHandler implements HttpHandler {
+/** A partial WebDav implementation based on ACR. */
+public class CmsAcrHttpHandler extends DavHttpHandler {
        private ProvidedRepository contentRepository;
 
        @Override
-       public void handle(HttpExchange exchange) throws IOException {
-               String method = exchange.getRequestMethod();
-               if (DavMethod.PROPFIND.name().equals(method)) {
-                       handlePROPFIND(exchange);
-               } else if (HttpMethod.GET.name().equals(method)) {
-                       handleGET(exchange);
-               } else {
-                       throw new IllegalArgumentException("Unsupported method " + method);
+       protected void handleGET(HttpExchange exchange, String path) throws IOException {
+               ContentSession session = RemoteAuthUtils.doAs(() -> contentRepository.get(),
+                               new RemoteAuthHttpExchange(exchange));
+               if (!session.exists(path)) // not found
+                       throw new ContentNotFoundException(session, path);
+               Content content = session.get(path);
+               Optional<Long> size = content.get(DName.getcontentlength, Long.class);
+               try (InputStream in = content.open(InputStream.class)) {
+                       exchange.sendResponseHeaders(HttpResponseStatus.OK.getCode(), size.orElse(0l));
+                       StreamUtils.copy(in, exchange.getResponseBody());
+               } catch (IOException e) {
+                       throw new RuntimeException("Cannot process " + path, e);
                }
-
        }
 
-       protected void handlePROPFIND(HttpExchange exchange) throws IOException {
-               String relativePath = HttpServerUtils.relativize(exchange);
-
-               DavDepth depth = DavDepth.fromHttpExchange(exchange);
-               if (depth == null) {
-                       // default, as per http://www.webdav.org/specs/rfc4918.html#METHOD_PROPFIND
-                       depth = DavDepth.DEPTH_INFINITY;
-               }
-
+       @Override
+       protected CompletableFuture<Void> handlePROPFIND(HttpExchange exchange, String path, DavPropfind davPropfind,
+                       Consumer<DavResponse> consumer) throws IOException {
                ContentSession session = RemoteAuthUtils.doAs(() -> contentRepository.get(),
                                new RemoteAuthHttpExchange(exchange));
-
-               String path = ContentUtils.ROOT_SLASH + relativePath;
-               if (!session.exists(path)) {// not found
-                       exchange.sendResponseHeaders(HttpResponseStatus.NOT_FOUND.getCode(), -1);
-                       return;
-               }
+               if (!session.exists(path)) // not found
+                       throw new ContentNotFoundException(session, path);
                Content content = session.get(path);
 
                CompletableFuture<Void> published = new CompletableFuture<Void>();
-
-               try (InputStream in = exchange.getRequestBody()) {
-                       DavPropfind davPropfind = DavPropfind.load(depth, in);
-                       MultiStatusWriter msWriter = new MultiStatusWriter();
-                       ForkJoinPool.commonPool().execute(() -> {
-                               publishDavResponses(content, davPropfind, msWriter);
-                               published.complete(null);
-                       });
-                       exchange.sendResponseHeaders(HttpResponseStatus.MULTI_STATUS.getCode(), 0l);
-                       try (OutputStream out = exchange.getResponseBody()) {
-                               msWriter.process(session, out, published.minimalCompletionStage(), davPropfind.isPropname());
-                       }
-               }
+               ForkJoinPool.commonPool().execute(() -> {
+                       publishDavResponses(content, davPropfind, consumer);
+                       published.complete(null);
+               });
+               return published;
        }
 
        protected void publishDavResponses(Content content, DavPropfind davPropfind, Consumer<DavResponse> consumer) {
@@ -114,7 +94,7 @@ public class CmsAcrHttpHandler implements HttpHandler {
                                        Object value = content.get(key);
                                        processMapEntry(davResponse, key, value);
                                }
-                               if (DavXmlElement.resourcetype.qName().equals(key)) {
+                               if (DName.resourcetype.qName().equals(key)) {
                                        davResponse.getResourceTypes().addAll(content.getContentClasses());
                                }
                        }
@@ -152,20 +132,6 @@ public class CmsAcrHttpHandler implements HttpHandler {
 
        }
 
-       protected void handleGET(HttpExchange exchange) {
-               String relativePath = HttpServerUtils.relativize(exchange);
-               ContentSession session = RemoteAuthUtils.doAs(() -> contentRepository.get(),
-                               new RemoteAuthHttpExchange(exchange));
-               Content content = session.get(ContentUtils.ROOT_SLASH + relativePath);
-               Optional<Long> size = content.get(DName.getcontentlength, Long.class);
-               try (InputStream in = content.open(InputStream.class)) {
-                       exchange.sendResponseHeaders(HttpResponseStatus.OK.getCode(), size.orElse(0l));
-                       StreamUtils.copy(in, exchange.getResponseBody());
-               } catch (IOException e) {
-                       throw new RuntimeException("Cannot process " + relativePath, e);
-               }
-       }
-
        public void setContentRepository(ProvidedRepository contentRepository) {
                this.contentRepository = contentRepository;
        }