X-Git-Url: https://git.argeo.org/?a=blobdiff_plain;f=org.argeo.cms%2Fsrc%2Forg%2Fargeo%2Fcms%2Fgcr%2Ffs%2FFsContent.java;h=5efa65959b50a86affbf5e0b3e0b5bcc246c339d;hb=e5a22cdc7d0f4918f2740c626e1ab6384bd5ee44;hp=2766d0e3eaaf81ebff14fa5e28e4741ddde53de2;hpb=5a36795f16b1b2a58188db84d6546b501626bda8;p=lgpl%2Fargeo-commons.git diff --git a/org.argeo.cms/src/org/argeo/cms/gcr/fs/FsContent.java b/org.argeo.cms/src/org/argeo/cms/gcr/fs/FsContent.java index 2766d0e3e..5efa65959 100644 --- a/org.argeo.cms/src/org/argeo/cms/gcr/fs/FsContent.java +++ b/org.argeo.cms/src/org/argeo/cms/gcr/fs/FsContent.java @@ -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 org.argeo.api.gcr.AbstractContent; +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.ContentSession; +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 BASIC_KEYS = new HashSet<>( - Arrays.asList("basic:creationTime", "basic:lastModifiedTime", "basic:size", "basic:fileKey")); - private static final Set POSIX_KEYS; + private static final Map BASIC_KEYS; + private static final Map 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 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 get(String key, Class clss) { + public A get(QName key, Class 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); } @@ -84,24 +104,108 @@ public class FsContent extends AbstractContent implements Content { } @Override - public ContentSession getSession() { - return contentSession; - } - - @Override - protected Iterable keys() { - Set result = new HashSet<>(isPosix() ? POSIX_KEYS : BASIC_KEYS); + protected Iterable keys() { + Set 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 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; + } + }