HTTP GET support for ACR.
authorMathieu Baudier <mbaudier@argeo.org>
Thu, 15 Sep 2022 04:11:27 +0000 (06:11 +0200)
committerMathieu Baudier <mbaudier@argeo.org>
Thu, 15 Sep 2022 04:11:27 +0000 (06:11 +0200)
org.argeo.api.acr/src/org/argeo/api/acr/CrName.java
org.argeo.api.cms/src/org/argeo/api/cms/CmsConstants.java
org.argeo.cms/OSGI-INF/cmsAcrHttpHandler.xml
org.argeo.cms/src/org/argeo/cms/acr/CmsContentSession.java
org.argeo.cms/src/org/argeo/cms/internal/runtime/CmsAcrHttpHandler.java
org.argeo.util/src/org/argeo/util/dav/DavResponse.java
org.argeo.util/src/org/argeo/util/dav/DavServerHandler.java
org.argeo.util/src/org/argeo/util/dav/MultiStatusReader.java
org.argeo.util/src/org/argeo/util/http/HttpResponseStatus.java
swt/org.argeo.cms.swt/src/org/argeo/cms/swt/acr/AcrSwtImageManager.java

index 22aa82b9191db20f40698ee8c3a31b56c0bb9918..3fe3462b97fc6f7b1b0459e242efc14a9135c874 100644 (file)
@@ -1,9 +1,7 @@
 package org.argeo.api.acr;
 
-import javax.xml.namespace.QName;
-
 /** Standard names. */
-public enum CrName {
+public enum CrName implements QNamed {
 
        /*
         * TYPES
@@ -14,7 +12,7 @@ public enum CrName {
         * ATTRIBUTES
         */
        uuid, // the UUID of a content
-       mount,
+       mount, // a mount point
        cc, // content class
 
        /*
@@ -45,24 +43,24 @@ public enum CrName {
        public final static String ROLE_NAMESPACE_URI = "http://www.argeo.org/ns/role";
        public final static String ROLE_DEFAULT_PREFIX = "role";
 
-       private final ContentName value;
-
-       CrName() {
-               value = new ContentName(CR_NAMESPACE_URI, name(), RuntimeNamespaceContext.getNamespaceContext());
-       }
-
-       public QName qName() {
-               return value;
-       }
+//     private final ContentName value;
 
-//     @Override
-//     public String getNamespaceURI() {
-//             return CR_NAMESPACE_URI;
+//     CrName() {
+//             value = new ContentName(CR_NAMESPACE_URI, name(), RuntimeNamespaceContext.getNamespaceContext());
 //     }
 //
-//     @Override
-//     public String getDefaultPrefix() {
-//             return CR_DEFAULT_PREFIX;
+//     public QName qName() {
+//             return value;
 //     }
 
+       @Override
+       public String getNamespace() {
+               return CR_NAMESPACE_URI;
+       }
+
+       @Override
+       public String getDefaultPrefix() {
+               return CR_DEFAULT_PREFIX;
+       }
+
 }
index 29cf12e2b0c5f33a68a589aecdc3a397d9ba1399..bae874b1652e85f4ac28d372e0aa206b19abaf39 100644 (file)
@@ -36,12 +36,11 @@ public interface CmsConstants {
        String PUBLIC_WORKSPACE = "public";
        String SECURITY_WORKSPACE = "security";
        String MIGRATION_WORKSPACE = "migration";
-       
+
        /*
         * ACR CONVENTIONS
         */
        String SRV_BASE = "/srv";
-       
 
        /*
         * BASE DNs
@@ -76,6 +75,7 @@ public interface CmsConstants {
        String PATH_JCR = "/jcr";
        String PATH_FILES = "/files";
        // String PATH_JCR_PUB = "/pub";
+       String PATH_API_ACR = "/api/acr";
 
        /*
         * FILE SYSTEMS
index 35b14493517cfdeec60460753dc601066fe2e160..6b05a900445c9fe94c0372688b87444a5ccc892b 100644 (file)
@@ -5,4 +5,5 @@
       <provide interface="com.sun.net.httpserver.HttpHandler"/>
    </service>
    <property name="context.path" type="String" value="/api/acr" />
+   <reference bind="setContentRepository" cardinality="1..1" interface="org.argeo.api.acr.spi.ProvidedRepository" name="ProvidedRepository" policy="static"/>
 </scr:component>
index 9f10d3f3176ce2d127b679035f42b1d323e26d9b..757dad143a7ec3fe59a39d26b7e83b5b9076bf09 100644 (file)
@@ -61,6 +61,8 @@ class CmsContentSession implements ProvidedSession {
 
        @Override
        public Content get(String path) {
+               if (!path.startsWith(ContentUtils.ROOT_SLASH))
+                       throw new IllegalArgumentException(path + " is not an absolute path");
                ContentProvider contentProvider = contentRepository.getMountManager().findContentProvider(path);
                String mountPath = contentProvider.getMountPath();
                String relativePath = extractRelativePath(mountPath, path);
index d9fa9e751d64394f37f5651fc0349afdc4580b33..7799a8c4eea29f9f1547721ecbd1c7d431cd847c 100644 (file)
@@ -1,7 +1,43 @@
 package org.argeo.cms.internal.runtime;
 
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Optional;
+
+import org.argeo.api.acr.Content;
+import org.argeo.api.acr.ContentSession;
+import org.argeo.api.acr.CrName;
+import org.argeo.api.acr.spi.ProvidedRepository;
+import org.argeo.cms.acr.ContentUtils;
+import org.argeo.cms.auth.RemoteAuthUtils;
+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 com.sun.net.httpserver.HttpExchange;
+
+public class CmsAcrHttpHandler extends DavServerHandler {
+       private ProvidedRepository contentRepository;
+
+       @Override
+       protected void handleGET(HttpExchange exchange) {
+               ContentSession session = RemoteAuthUtils.doAs(() -> contentRepository.get(),
+                               new RemoteAuthHttpExchange(exchange));
+               String relativePath = HttpServerUtils.relativize(exchange);
+               Content content = session.get(ContentUtils.ROOT_SLASH + relativePath);
+               Optional<Long> size = content.get(CrName.size, Long.class);
+               try (InputStream in = content.open(InputStream.class)) {
+                       exchange.sendResponseHeaders(HttpResponseStatus.OK.getStatusCode(), size.orElse(0l));
+                       StreamUtils.copy(in, exchange.getResponseBody());
+               } catch (IOException e) {
+                       throw new RuntimeException("Cannot process " + relativePath, e);
+               }
+       }
 
-public class CmsAcrHttpHandler extends DavServerHandler  {
+       public void setContentRepository(ProvidedRepository contentRepository) {
+               this.contentRepository = contentRepository;
+       }
 
 }
index 22ffa17d13038093fb4277a24af210dfc3386b65..424a0e8b711979e346e42625ee99cc5d03edc998 100644 (file)
@@ -10,7 +10,7 @@ import java.util.Set;
 import javax.xml.namespace.QName;
 
 public class DavResponse {
-       final static String MODE_DAV_NAMESPACE = "http://apache.org/dav/props/";
+       final static String MOD_DAV_NAMESPACE = "http://apache.org/dav/props/";
 
        private String href;
        private boolean collection;
index f9fba4761c62b26a91616f3afa64a0e69609ef75..29d689dbb233c7dca5a38163f6b3a8e281c4d33d 100644 (file)
@@ -13,17 +13,21 @@ public class DavServerHandler implements HttpHandler {
        public void handle(HttpExchange exchange) throws IOException {
                String method = exchange.getRequestMethod();
                if (DavMethod.PROPFIND.name().equals(method)) {
-                       handle(exchange);
+                       handlePROPFIND(exchange);
                } else if (HttpMethod.GET.name().equals(method)) {
-                       exchange.getResponseBody().write("Hello Dav!".getBytes());
+                       handleGET(exchange);
                } else {
                        throw new IllegalArgumentException("Unsupported method " + method);
                }
 
        }
 
+       protected void handleGET(HttpExchange exchange) {
+               throw new UnsupportedOperationException();
+       }
+
        protected DavResponse handlePROPFIND(HttpExchange exchange) {
-               return null;
+               throw new UnsupportedOperationException();
        }
 
 }
index 966100e4aa1ee73b4a18e9637b589c1cbd822d68..cc79215234f09310540b127ea6b11a73c785e9cc 100644 (file)
@@ -98,7 +98,7 @@ class MultiStatusReader implements Iterator<DavResponse> {
                                                                        value = reader.getText();
                                                        }
 
-                                                       if (name.getNamespaceURI().equals(DavResponse.MODE_DAV_NAMESPACE))
+                                                       if (name.getNamespaceURI().equals(DavResponse.MOD_DAV_NAMESPACE))
                                                                continue elements; // skip mod_dav properties
 
                                                        assert currentResponse != null;
index ec67cce5e366a24c6611da30997795b34ca3bc19..db7fbe30bbc1df47192f7e7c6daebc0748dbae8d 100644 (file)
@@ -6,9 +6,12 @@ package org.argeo.util.http;
  * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Status
  */
 public enum HttpResponseStatus {
+       // Successful responses (200–299)
+       OK(200), //
+       // Client error responses (400–499)
        UNAUTHORIZED(401), //
        FORBIDDEN(403), //
-       NOT_FOUND(404),//
+       NOT_FOUND(404), //
        ;
 
        private final int statusCode;
index e683d9630610a5d97e37eef59b2768e082357eed..78a9930051657ed4669f4caf196113f6c2c44ee7 100644 (file)
@@ -41,7 +41,7 @@ public class AcrSwtImageManager extends AbstractSwtImageManager<Content> {
        /** A path in the node repository */
        protected String getDataPath(Content node) {
                // TODO make it more configurable?
-               StringBuilder buf = new StringBuilder(CmsConstants.PATH_DATA);
+               StringBuilder buf = new StringBuilder(CmsConstants.PATH_API_ACR);
                buf.append(node.getPath());
                return buf.toString();
        }