Introduce namespace support
[lgpl/argeo-commons.git] / org.argeo.cms / src / org / argeo / cms / gcr / fs / FsContent.java
index bb131f5aac146ca0ac2dfd24847d6e9a5420b283..5efa65959b50a86affbf5e0b3e0b5bcc246c339d 100644 (file)
@@ -1,41 +1,69 @@
 package org.argeo.cms.gcr.fs;
 
 import java.io.IOException;
+import java.nio.ByteBuffer;
 import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.attribute.FileTime;
 import java.nio.file.attribute.UserDefinedFileAttributeView;
 import java.time.Instant;
-import java.util.Arrays;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
+import java.util.Map;
 import java.util.Set;
 
+import javax.xml.namespace.QName;
+
 import org.argeo.api.gcr.Content;
+import org.argeo.api.gcr.ContentName;
 import org.argeo.api.gcr.ContentResourceException;
-import org.argeo.api.gcr.ContentSystemProvider;
+import org.argeo.api.gcr.CrName;
 import org.argeo.api.gcr.spi.AbstractContent;
+import org.argeo.api.gcr.spi.ProvidedContent;
+import org.argeo.api.gcr.spi.ProvidedSession;
+import org.argeo.util.FsUtils;
+
+public class FsContent extends AbstractContent implements ProvidedContent {
+       private final static String USER_ = "user:";
 
-public class FsContent extends AbstractContent implements Content {
-       private static final Set<String> BASIC_KEYS = new HashSet<>(
-                       Arrays.asList("basic:creationTime", "basic:lastModifiedTime", "basic:size", "basic:fileKey"));
-       private static final Set<String> POSIX_KEYS;
+       private static final Map<QName, String> BASIC_KEYS;
+       private static final Map<QName, String> POSIX_KEYS;
        static {
-               POSIX_KEYS = new HashSet<>(BASIC_KEYS);
-               POSIX_KEYS.add("owner:owner");
-               POSIX_KEYS.add("posix:group");
-               POSIX_KEYS.add("posix:permissions");
+               BASIC_KEYS = new HashMap<>();
+               BASIC_KEYS.put(CrName.CREATION_TIME.get(), "basic:creationTime");
+               BASIC_KEYS.put(CrName.LAST_MODIFIED_TIME.get(), "basic:lastModifiedTime");
+               BASIC_KEYS.put(CrName.SIZE.get(), "basic:size");
+               BASIC_KEYS.put(CrName.FILE_KEY.get(), "basic:fileKey");
+
+               POSIX_KEYS = new HashMap<>(BASIC_KEYS);
+               POSIX_KEYS.put(CrName.OWNER.get(), "owner:owner");
+               POSIX_KEYS.put(CrName.GROUP.get(), "posix:group");
+               POSIX_KEYS.put(CrName.PERMISSIONS.get(), "posix:permissions");
        }
 
-       private FsContentSession contentSession;
+       private final ProvidedSession session;
+       private final FsContentProvider provider;
        private final Path path;
+       private final boolean isRoot;
+       private final QName name;
 
-       public FsContent(FsContentSession contentSession, Path path) {
-               super();
-               this.contentSession = contentSession;
+       protected FsContent(ProvidedSession session, FsContentProvider contentProvider, Path path) {
+               this.session = session;
+               this.provider = contentProvider;
                this.path = path;
+               this.isRoot = contentProvider.isRoot(path);
+               // TODO check file names with ':' ?
+               if (isRoot)
+                       this.name = CrName.ROOT.get();
+               else
+                       this.name = session.parsePrefixedName(path.getFileName().toString());
+       }
+
+       protected FsContent(FsContent context, Path path) {
+               this(context.getSession(), context.getProvider(), path);
        }
 
        private boolean isPosix() {
@@ -43,28 +71,20 @@ public class FsContent extends AbstractContent implements Content {
        }
 
        @Override
-       public Iterator<Content> iterator() {
-               if (Files.isDirectory(path)) {
-                       try {
-                               return Files.list(path).map((p) -> (Content) new FsContent(contentSession, p)).iterator();
-                       } catch (IOException e) {
-                               throw new ContentResourceException("Cannot list " + path, e);
-                       }
-               } else {
-                       return Collections.emptyIterator();
-               }
+       public QName getName() {
+               return name;
        }
 
-       @Override
-       public String getName() {
-               return path.getFileName().toString();
-       }
+       /*
+        * ATTRIBUTES
+        */
 
        @Override
-       public <A> A get(String key, Class<A> clss) {
+       public <A> A get(QName key, Class<A> clss) {
                Object value;
                try {
-                       value = Files.getAttribute(path, key);
+                       // We need to add user: when accessing via Files#getAttribute
+                       value = Files.getAttribute(path, toFsAttributeKey(key));
                } catch (IOException e) {
                        throw new ContentResourceException("Cannot retrieve attribute " + key + " for " + path, e);
                }
@@ -83,21 +103,109 @@ public class FsContent extends AbstractContent implements Content {
                return (A) value;
        }
 
-
        @Override
-       protected Iterable<String> keys() {
-               Set<String> result = new HashSet<>(isPosix() ? POSIX_KEYS : BASIC_KEYS);
+       protected Iterable<QName> keys() {
+               Set<QName> result = new HashSet<>(isPosix() ? POSIX_KEYS.keySet() : BASIC_KEYS.keySet());
                UserDefinedFileAttributeView udfav = Files.getFileAttributeView(path, UserDefinedFileAttributeView.class);
                if (udfav != null) {
                        try {
                                for (String name : udfav.list()) {
-                                       result.add("user:" + name);
+                                       result.add(session.parsePrefixedName(name));
                                }
                        } catch (IOException e) {
-                               throw new ContentResourceException("Cannot liast attributes for " + path, e);
+                               throw new ContentResourceException("Cannot list attributes for " + path, e);
                        }
                }
                return result;
        }
 
+       @Override
+       protected void removeAttr(QName key) {
+               UserDefinedFileAttributeView udfav = Files.getFileAttributeView(path, UserDefinedFileAttributeView.class);
+               try {
+                       udfav.delete(session.toPrefixedName(key));
+               } catch (IOException e) {
+                       throw new ContentResourceException("Cannot delete attribute " + key + " for " + path, e);
+               }
+       }
+
+       @Override
+       public Object put(QName key, Object value) {
+               Object previous = get(key);
+               UserDefinedFileAttributeView udfav = Files.getFileAttributeView(path, UserDefinedFileAttributeView.class);
+               ByteBuffer bb = ByteBuffer.wrap(value.toString().getBytes(StandardCharsets.UTF_8));
+               try {
+                       int size = udfav.write(session.toPrefixedName(key), bb);
+               } catch (IOException e) {
+                       throw new ContentResourceException("Cannot delete attribute " + key + " for " + path, e);
+               }
+               return previous;
+       }
+
+       protected String toFsAttributeKey(QName key) {
+               if (POSIX_KEYS.containsKey(key))
+                       return POSIX_KEYS.get(key);
+               else
+                       return USER_ + session.toPrefixedName(key);
+       }
+
+       /*
+        * CONTENT OPERATIONS
+        */
+       @Override
+       public Iterator<Content> iterator() {
+               if (Files.isDirectory(path)) {
+                       try {
+                               return Files.list(path).map((p) -> (Content) new FsContent(this, p)).iterator();
+                       } catch (IOException e) {
+                               throw new ContentResourceException("Cannot list " + path, e);
+                       }
+               } else {
+                       return Collections.emptyIterator();
+               }
+       }
+
+       @Override
+       public Content add(QName name, QName... classes) {
+               try {
+                       Path newPath = path.resolve(session.toPrefixedName(name));
+                       if (ContentName.contains(classes, CrName.COLLECTION.get()))
+                               Files.createDirectory(newPath);
+                       else
+                               Files.createFile(newPath);
+
+//             for(ContentClass clss:classes) {
+//                     Files.setAttribute(newPath, name, newPath, null)
+//             }
+                       return new FsContent(this, newPath);
+               } catch (IOException e) {
+                       throw new ContentResourceException("Cannot create new content", e);
+               }
+       }
+
+       @Override
+       public void remove() {
+               FsUtils.delete(path);
+       }
+
+       @Override
+       public Content getParent() {
+               if (isRoot)
+                       return null;// TODO deal with mounts
+               return new FsContent(this, path.getParent());
+       }
+
+       /*
+        * ACCESSORS
+        */
+       @Override
+       public ProvidedSession getSession() {
+               return session;
+       }
+
+       @Override
+       public FsContentProvider getProvider() {
+               return provider;
+       }
+
 }