]> git.argeo.org Git - lgpl/argeo-commons.git/blobdiff - org.argeo.cms/src/org/argeo/cms/acr/fs/FsContent.java
Introduce directory content provider
[lgpl/argeo-commons.git] / org.argeo.cms / src / org / argeo / cms / acr / fs / FsContent.java
index a2cc52c42850f54bd2d7e25258b3cab866f10993..d0df8845f308a4fa5befbef1c60ef5ca953e2265 100644 (file)
@@ -11,10 +11,12 @@ import java.nio.file.Path;
 import java.nio.file.attribute.FileTime;
 import java.nio.file.attribute.UserDefinedFileAttributeView;
 import java.time.Instant;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 import java.util.Set;
@@ -24,15 +26,16 @@ import javax.xml.namespace.QName;
 import org.argeo.api.acr.Content;
 import org.argeo.api.acr.ContentName;
 import org.argeo.api.acr.ContentResourceException;
-import org.argeo.api.acr.ContentUtils;
 import org.argeo.api.acr.CrName;
 import org.argeo.api.acr.NamespaceUtils;
-import org.argeo.api.acr.spi.AbstractContent;
 import org.argeo.api.acr.spi.ContentProvider;
 import org.argeo.api.acr.spi.ProvidedContent;
 import org.argeo.api.acr.spi.ProvidedSession;
+import org.argeo.cms.acr.AbstractContent;
+import org.argeo.cms.acr.ContentUtils;
 import org.argeo.util.FsUtils;
 
+/** Content persisted as a filesystem {@link Path}. */
 public class FsContent extends AbstractContent implements ProvidedContent {
        final static String USER_ = "user:";
 
@@ -51,28 +54,32 @@ public class FsContent extends AbstractContent implements ProvidedContent {
                POSIX_KEYS.put(CrName.PERMISSIONS.get(), "posix:permissions");
        }
 
-       private final ProvidedSession session;
        private final FsContentProvider provider;
        private final Path path;
        private final boolean isRoot;
        private final QName name;
 
        protected FsContent(ProvidedSession session, FsContentProvider contentProvider, Path path) {
-               this.session = session;
+               super(session);
                this.provider = contentProvider;
                this.path = path;
-               this.isRoot = contentProvider.isRoot(path);
+               this.isRoot = contentProvider.isMountRoot(path);
                // TODO check file names with ':' ?
                if (isRoot) {
                        String mountPath = provider.getMountPath();
-                       if (mountPath != null) {
+                       if (mountPath != null && !mountPath.equals("/")) {
                                Content mountPoint = session.getMountPoint(mountPath);
                                this.name = mountPoint.getName();
                        } else {
                                this.name = CrName.ROOT.get();
                        }
                } else {
-                       QName providerName = NamespaceUtils.parsePrefixedName(provider, path.getFileName().toString());
+
+                       // TODO should we support prefixed name for known types?
+                       // QName providerName = NamespaceUtils.parsePrefixedName(provider,
+                       // path.getFileName().toString());
+                       QName providerName = new QName(path.getFileName().toString());
+                       // TODO remove extension if mounted?
                        this.name = new ContentName(providerName, session);
                }
        }
@@ -94,12 +101,32 @@ public class FsContent extends AbstractContent implements ProvidedContent {
         * ATTRIBUTES
         */
 
+       @SuppressWarnings("unchecked")
        @Override
        public <A> Optional<A> get(QName key, Class<A> clss) {
                Object value;
                try {
                        // We need to add user: when accessing via Files#getAttribute
-                       value = Files.getAttribute(path, toFsAttributeKey(key));
+
+                       if (POSIX_KEYS.containsKey(key)) {
+                               value = Files.getAttribute(path, toFsAttributeKey(key));
+                       } else {
+                               UserDefinedFileAttributeView udfav = Files.getFileAttributeView(path,
+                                               UserDefinedFileAttributeView.class);
+                               String prefixedName = NamespaceUtils.toPrefixedName(provider, key);
+                               if (!udfav.list().contains(prefixedName))
+                                       return Optional.empty();
+                               ByteBuffer buf = ByteBuffer.allocate(udfav.size(prefixedName));
+                               udfav.read(prefixedName, buf);
+                               buf.flip();
+                               if (buf.hasArray())
+                                       value = buf.array();
+                               else {
+                                       byte[] arr = new byte[buf.remaining()];
+                                       buf.get(arr);
+                                       value = arr;
+                               }
+                       }
                } catch (IOException e) {
                        throw new ContentResourceException("Cannot retrieve attribute " + key + " for " + path, e);
                }
@@ -133,7 +160,7 @@ public class FsContent extends AbstractContent implements ProvidedContent {
                        try {
                                for (String name : udfav.list()) {
                                        QName providerName = NamespaceUtils.parsePrefixedName(provider, name);
-                                       QName sessionName = new ContentName(providerName, session);
+                                       QName sessionName = new ContentName(providerName, getSession());
                                        result.add(sessionName);
                                }
                        } catch (IOException e) {
@@ -159,7 +186,7 @@ public class FsContent extends AbstractContent implements ProvidedContent {
                UserDefinedFileAttributeView udfav = Files.getFileAttributeView(path, UserDefinedFileAttributeView.class);
                ByteBuffer bb = ByteBuffer.wrap(value.toString().getBytes(StandardCharsets.UTF_8));
                try {
-                       int size = udfav.write(NamespaceUtils.toPrefixedName(provider, key), bb);
+                       udfav.write(NamespaceUtils.toPrefixedName(provider, key), bb);
                } catch (IOException e) {
                        throw new ContentResourceException("Cannot delete attribute " + key + " for " + path, e);
                }
@@ -185,9 +212,9 @@ public class FsContent extends AbstractContent implements ProvidedContent {
                                        Optional<String> isMount = fsContent.get(CrName.MOUNT.get(), String.class);
                                        if (isMount.orElse("false").equals("true")) {
                                                QName[] classes = null;
-                                               ContentProvider contentProvider = session.getRepository().getMountContentProvider(fsContent,
-                                                               false, classes);
-                                               Content mountedContent = contentProvider.get(session, fsContent.getPath(), "");
+                                               ContentProvider contentProvider = getSession().getRepository()
+                                                               .getMountContentProvider(fsContent, false, classes);
+                                               Content mountedContent = contentProvider.get(getSession(), "");
                                                return mountedContent;
                                        } else {
                                                return (Content) fsContent;
@@ -219,9 +246,10 @@ public class FsContent extends AbstractContent implements ProvidedContent {
                        throw new ContentResourceException("Cannot create new content", e);
                }
 
-               if (session.getRepository().shouldMount(classes)) {
-                       ContentProvider contentProvider = session.getRepository().getMountContentProvider(fsContent, true, classes);
-                       Content mountedContent = contentProvider.get(session, fsContent.getPath(), "");
+               if (getSession().getRepository().shouldMount(classes)) {
+                       ContentProvider contentProvider = getSession().getRepository().getMountContentProvider(fsContent, true,
+                                       classes);
+                       Content mountedContent = contentProvider.get(getSession(), "");
                        fsContent.put(CrName.MOUNT.get(), "true");
                        return mountedContent;
 
@@ -239,14 +267,15 @@ public class FsContent extends AbstractContent implements ProvidedContent {
        public Content getParent() {
                if (isRoot) {
                        String mountPath = provider.getMountPath();
-                       if (mountPath == null)
+                       if (mountPath == null || mountPath.equals("/"))
                                return null;
                        String[] parent = ContentUtils.getParentPath(mountPath);
-                       return session.get(parent[0]);
+                       return getSession().get(parent[0]);
                }
                return new FsContent(this, path.getParent());
        }
 
+       @SuppressWarnings("unchecked")
        @Override
        public <C extends Closeable> C open(Class<C> clss) throws IOException, IllegalArgumentException {
                if (InputStream.class.isAssignableFrom(clss)) {
@@ -272,13 +301,22 @@ public class FsContent extends AbstractContent implements ProvidedContent {
        }
 
        /*
-        * ACCESSORS
+        * TYPING
         */
+
        @Override
-       public ProvidedSession getSession() {
-               return session;
+       public List<QName> getTypes() {
+               List<QName> res = new ArrayList<>();
+               if (Files.isDirectory(path))
+                       res.add(CrName.COLLECTION.get());
+               // TODO add other types
+               return res;
        }
 
+       /*
+        * ACCESSORS
+        */
+
        @Override
        public FsContentProvider getProvider() {
                return provider;