package org.argeo.cms.acr.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.UserDefinedFileAttributeView;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NavigableMap;
+import java.util.Objects;
+import java.util.TreeMap;
+import java.util.stream.Collectors;
-import org.argeo.api.acr.Content;
+import org.argeo.api.acr.ArgeoNamespace;
import org.argeo.api.acr.ContentResourceException;
+import org.argeo.api.acr.NamespaceUtils;
+import org.argeo.api.acr.RuntimeNamespaceContext;
import org.argeo.api.acr.spi.ContentProvider;
+import org.argeo.api.acr.spi.ProvidedContent;
import org.argeo.api.acr.spi.ProvidedSession;
+/** Access a file system as a {@link ContentProvider}. */
public class FsContentProvider implements ContentProvider {
- private final Path rootPath;
+ final static String XMLNS_ = "xmlns:";
- public FsContentProvider(Path rootPath) {
- super();
+ protected String mountPath;
+ protected Path rootPath;
+
+ private NavigableMap<String, String> prefixes = new TreeMap<>();
+
+ public FsContentProvider(String mountPath, Path rootPath) {
+ Objects.requireNonNull(mountPath);
+ Objects.requireNonNull(rootPath);
+
+ this.mountPath = mountPath;
this.rootPath = rootPath;
+ // FIXME make it more robust
+ initNamespaces();
+ }
+
+ protected FsContentProvider() {
+
}
- boolean isRoot(Path path) {
+ protected void initNamespaces() {
+ try {
+ UserDefinedFileAttributeView udfav = Files.getFileAttributeView(rootPath,
+ UserDefinedFileAttributeView.class);
+ if (udfav == null)
+ return;
+ for (String name : udfav.list()) {
+ if (name.startsWith(XMLNS_)) {
+ ByteBuffer buf = ByteBuffer.allocate(udfav.size(name));
+ udfav.read(name, buf);
+ buf.flip();
+ String namespace = StandardCharsets.UTF_8.decode(buf).toString();
+ String prefix = name.substring(XMLNS_.length());
+ prefixes.put(prefix, namespace);
+ }
+ }
+
+ // defaults
+ addDefaultNamespace(udfav, ArgeoNamespace.CR_DEFAULT_PREFIX, ArgeoNamespace.CR_NAMESPACE_URI);
+ addDefaultNamespace(udfav, "basic", ArgeoNamespace.CR_NAMESPACE_URI);
+ addDefaultNamespace(udfav, "owner", ArgeoNamespace.CR_NAMESPACE_URI);
+ addDefaultNamespace(udfav, "posix", ArgeoNamespace.CR_NAMESPACE_URI);
+ } catch (IOException e) {
+ throw new RuntimeException("Cannot read namespaces from " + rootPath, e);
+ }
+
+ }
+
+ protected void addDefaultNamespace(UserDefinedFileAttributeView udfav, String prefix, String namespace)
+ throws IOException {
+ if (!prefixes.containsKey(prefix)) {
+ ByteBuffer bb = ByteBuffer.wrap(namespace.getBytes(StandardCharsets.UTF_8));
+ udfav.write(XMLNS_ + prefix, bb);
+ prefixes.put(prefix, namespace);
+ }
+ }
+
+ public void registerPrefix(String prefix, String namespace) {
+ if (prefixes.containsKey(prefix))
+ prefixes.remove(prefix);
+ try {
+ UserDefinedFileAttributeView udfav = Files.getFileAttributeView(rootPath,
+ UserDefinedFileAttributeView.class);
+ addDefaultNamespace(udfav, prefix, namespace);
+ } catch (IOException e) {
+ throw new RuntimeException("Cannot register namespace " + prefix + " " + namespace + " on " + rootPath, e);
+ }
+
+ }
+
+ @Override
+ public String getMountPath() {
+ return mountPath;
+ }
+
+ boolean isMountBase(Path path) {
try {
return Files.isSameFile(rootPath, path);
} catch (IOException e) {
}
@Override
- public Content get(ProvidedSession session, String mountPath, String relativePath) {
+ public ProvidedContent get(ProvidedSession session, String relativePath) {
return new FsContent(session, this, rootPath.resolve(relativePath));
}
+
+ @Override
+ public boolean exists(ProvidedSession session, String relativePath) {
+ return Files.exists(rootPath.resolve(relativePath));
+ }
+
+ /*
+ * NAMESPACE CONTEXT
+ */
+
+ @Override
+ public String getNamespaceURI(String prefix) {
+ return NamespaceUtils.getNamespaceURI((p) -> prefixes.get(p), prefix);
+ }
+
+ @Override
+ public Iterator<String> getPrefixes(String namespaceURI) {
+ Iterator<String> res = NamespaceUtils.getPrefixes((ns) -> prefixes.entrySet().stream()
+ .filter(e -> e.getValue().equals(ns)).map(Map.Entry::getKey).collect(Collectors.toUnmodifiableSet()),
+ namespaceURI);
+ if (!res.hasNext()) {
+ String prefix = RuntimeNamespaceContext.getNamespaceContext().getPrefix(namespaceURI);
+ if (prefix != null) {
+ registerPrefix(prefix, namespaceURI);
+ return getPrefixes(namespaceURI);
+ } else {
+ throw new IllegalArgumentException("Unknown namespace " + namespaceURI);
+ }
+ }
+ return res;
+ }
+
}