X-Git-Url: https://git.argeo.org/?a=blobdiff_plain;f=org.argeo.cms%2Fsrc%2Forg%2Fargeo%2Fcms%2Finternal%2Fruntime%2FCmsAcrHttpHandler.java;h=c80933a559753203cac8e50ebc95b98afd79fd42;hb=54df376a9c2dd458a82eaa09bfbb718fe699dd0d;hp=7799a8c4eea29f9f1547721ecbd1c7d431cd847c;hpb=b897c27d370ad4772b5ae4b2c22cc505ef5d1a3f;p=lgpl%2Fargeo-commons.git diff --git a/org.argeo.cms/src/org/argeo/cms/internal/runtime/CmsAcrHttpHandler.java b/org.argeo.cms/src/org/argeo/cms/internal/runtime/CmsAcrHttpHandler.java index 7799a8c4e..c80933a55 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/runtime/CmsAcrHttpHandler.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/runtime/CmsAcrHttpHandler.java @@ -2,40 +2,146 @@ package org.argeo.cms.internal.runtime; import java.io.IOException; import java.io.InputStream; +import java.util.Collection; +import java.util.Map; import java.util.Optional; +import java.util.StringJoiner; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ForkJoinPool; +import java.util.function.Consumer; + +import javax.xml.namespace.NamespaceContext; +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.CrName; +import org.argeo.api.acr.DName; +import org.argeo.api.acr.RuntimeNamespaceContext; import org.argeo.api.acr.spi.ProvidedRepository; -import org.argeo.cms.acr.ContentUtils; +import org.argeo.api.cms.CmsConstants; import org.argeo.cms.auth.RemoteAuthUtils; +import org.argeo.cms.dav.DavDepth; +import org.argeo.cms.dav.DavHttpHandler; +import org.argeo.cms.dav.DavPropfind; +import org.argeo.cms.dav.DavResponse; +import org.argeo.cms.http.HttpStatus; import org.argeo.cms.internal.http.RemoteAuthHttpExchange; -import org.argeo.util.StreamUtils; -import org.argeo.util.dav.DavServerHandler; -import org.argeo.util.http.HttpResponseStatus; -import org.argeo.util.http.HttpServerUtils; +import org.argeo.cms.util.StreamUtils; import com.sun.net.httpserver.HttpExchange; -public class CmsAcrHttpHandler extends DavServerHandler { +/** A partial WebDav implementation based on ACR. */ +public class CmsAcrHttpHandler extends DavHttpHandler { private ProvidedRepository contentRepository; @Override - protected void handleGET(HttpExchange exchange) { + protected NamespaceContext getNamespaceContext(HttpExchange httpExchange, String path) { + // TODO be smarter? + return RuntimeNamespaceContext.getNamespaceContext(); + } + + @Override + protected void handleGET(HttpExchange exchange, String path) throws IOException { ContentSession session = RemoteAuthUtils.doAs(() -> contentRepository.get(), new RemoteAuthHttpExchange(exchange)); - String relativePath = HttpServerUtils.relativize(exchange); - Content content = session.get(ContentUtils.ROOT_SLASH + relativePath); - Optional size = content.get(CrName.size, Long.class); + if (!session.exists(path)) // not found + throw new ContentNotFoundException(session, path); + Content content = session.get(path); + Optional size = content.get(DName.getcontentlength, Long.class); try (InputStream in = content.open(InputStream.class)) { - exchange.sendResponseHeaders(HttpResponseStatus.OK.getStatusCode(), size.orElse(0l)); + exchange.sendResponseHeaders(HttpStatus.OK.getCode(), size.orElse(0l)); StreamUtils.copy(in, exchange.getResponseBody()); } catch (IOException e) { - throw new RuntimeException("Cannot process " + relativePath, e); + throw new RuntimeException("Cannot process " + path, e); } } + @Override + protected CompletableFuture handlePROPFIND(HttpExchange exchange, String path, DavPropfind davPropfind, + Consumer consumer) 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); + + CompletableFuture published = new CompletableFuture(); + ForkJoinPool.commonPool().execute(() -> { + publishDavResponses(content, davPropfind, consumer); + published.complete(null); + }); + return published; + } + + protected void publishDavResponses(Content content, DavPropfind davPropfind, Consumer consumer) { + publishDavResponse(content, davPropfind, consumer, 0); + } + + protected void publishDavResponse(Content content, DavPropfind davPropfind, Consumer consumer, + int currentDepth) { + DavResponse davResponse = new DavResponse(); + String href = CmsConstants.PATH_API_ACR + content.getPath(); + davResponse.setHref(href); + if (content.hasContentClass(DName.collection)) + davResponse.setCollection(true); + if (davPropfind.isAllprop()) { + for (Map.Entry entry : content.entrySet()) { + davResponse.getPropertyNames(HttpStatus.OK).add(entry.getKey()); + processMapEntry(davResponse, entry.getKey(), entry.getValue()); + } + davResponse.getResourceTypes().addAll(content.getContentClasses()); + } else if (davPropfind.isPropname()) { + for (QName key : content.keySet()) { + davResponse.getPropertyNames(HttpStatus.OK).add(key); + } + } else { + for (QName key : davPropfind.getProps()) { + if (content.containsKey(key)) { + davResponse.getPropertyNames(HttpStatus.OK).add(key); + Object value = content.get(key); + processMapEntry(davResponse, key, value); + } else { + davResponse.getPropertyNames(HttpStatus.NOT_FOUND).add(key); + } + if (DName.resourcetype.qName().equals(key)) { + davResponse.getResourceTypes().addAll(content.getContentClasses()); + } + } + + } + + consumer.accept(davResponse); + + // recurse only on collections + if (content.hasContentClass(DName.collection)) { + if (davPropfind.getDepth() == DavDepth.DEPTH_INFINITY + || (davPropfind.getDepth() == DavDepth.DEPTH_1 && currentDepth == 0)) { + for (Content child : content) { + publishDavResponse(child, davPropfind, consumer, currentDepth + 1); + } + } + } + } + + protected void processMapEntry(DavResponse davResponse, QName key, Object value) { + // ignore content classes + if (DName.resourcetype.qName().equals(key)) + return; + String str; + if (value instanceof Collection) { + StringJoiner sj = new StringJoiner("\n"); + for (Object v : (Collection) value) { + sj.add(v.toString()); + } + str = sj.toString(); + } else { + str = value.toString(); + } + davResponse.getProperties().put(key, str); + + } + public void setContentRepository(ProvidedRepository contentRepository) { this.contentRepository = contentRepository; }