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() {
}
@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);
}
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;
+ }
+
}