shell.setText(basePath.toString());
shell.setLayout(new FillLayout());
- FsContentProvider contentSession = new FsContentProvider(null, basePath, true);
+ FsContentProvider contentSession = new FsContentProvider("/", basePath);
// GcrContentTreeView treeView = new GcrContentTreeView(shell, 0, contentSession.get("/"));
shell.setSize(shell.computeSize(800, 600));
import org.argeo.api.acr.Content;
+/** Utilities and routines around {@link Content}. */
public class ContentUtils {
public static void traverse(Content content, BiConsumer<Content, Integer> doIt) {
- traverse(content, doIt, 0);
+ traverse(content, doIt, (Integer) null);
}
- public static void traverse(Content content, BiConsumer<Content, Integer> doIt, int currentDepth) {
+ public static void traverse(Content content, BiConsumer<Content, Integer> doIt, Integer maxDepth) {
+ doTraverse(content, doIt, 0, maxDepth);
+ }
+
+ private static void doTraverse(Content content, BiConsumer<Content, Integer> doIt, int currentDepth,
+ Integer maxDepth) {
doIt.accept(content, currentDepth);
+ if (maxDepth != null && currentDepth == maxDepth)
+ return;
int nextDepth = currentDepth + 1;
for (Content child : content) {
- traverse(child, doIt, nextDepth);
+ doTraverse(child, doIt, nextDepth, maxDepth);
}
}
}
}
-
-
// public static <T> boolean isString(T t) {
// return t instanceof String;
// }
package org.argeo.cms.acr;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.util.Locale;
import java.util.Objects;
import javax.security.auth.Subject;
+import javax.security.auth.x500.X500Principal;
import org.argeo.api.acr.ContentSession;
import org.argeo.api.acr.spi.ProvidedRepository;
+import org.argeo.cms.acr.fs.FsContentProvider;
+import org.argeo.util.naming.LdapAttrs;
/**
* A standalone {@link ProvidedRepository} with a single {@link Subject} (which
return new CmsContentSession(this, subject, Locale.getDefault());
}
+ public static void main(String... args) {
+ Path homePath = Paths.get(System.getProperty("user.home"));
+ String username = System.getProperty("user.name");
+ X500Principal principal = new X500Principal(LdapAttrs.uid + "=" + username + ",dc=localhost");
+ Subject subject = new Subject();
+ subject.getPrincipals().add(principal);
+
+ SingleUserContentRepository contentRepository = new SingleUserContentRepository(subject);
+ FsContentProvider homeContentProvider = new FsContentProvider("/home", homePath);
+ contentRepository.addProvider(homeContentProvider);
+ Runtime.getRuntime().addShutdownHook(new Thread(() -> contentRepository.stop(), "Shutdown content repository"));
+ contentRepository.start();
+
+ ContentSession contentSession = contentRepository.get();
+ ContentUtils.traverse(contentSession.get("/"), (c, depth) -> ContentUtils.print(c, System.out, depth, false),
+ 2);
+
+ }
}
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:";
this.session = 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();
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);
}
}
* ATTRIBUTES
*/
+ @SuppressWarnings("unchecked")
@Override
public <A> Optional<A> get(QName key, Class<A> clss) {
Object value;
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);
}
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)) {
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;
private final String mountPath;
private final Path rootPath;
- private final boolean isRoot;
+// private final boolean isRoot;
private NavigableMap<String, String> prefixes = new TreeMap<>();
- public FsContentProvider(String mountPath, Path rootPath, boolean isRoot) {
+ public FsContentProvider(String mountPath, Path rootPath) {
+ Objects.requireNonNull(mountPath);
+ Objects.requireNonNull(rootPath);
+
this.mountPath = mountPath;
this.rootPath = rootPath;
- this.isRoot = isRoot;
+ // FIXME make it more robust
initNamespaces();
}
- protected void initNamespaces() {
+// @Deprecated
+// public FsContentProvider(String mountPath, Path rootPath, boolean isRoot) {
+// this.mountPath = mountPath;
+// this.rootPath = rootPath;
+//// this.isRoot = isRoot;
+//// initNamespaces();
+// }
+
+ private void initNamespaces() {
try {
UserDefinedFileAttributeView udfav = Files.getFileAttributeView(rootPath,
UserDefinedFileAttributeView.class);
- if(udfav==null)
+ if (udfav == null)
return;
for (String name : udfav.list()) {
if (name.startsWith(XMLNS_)) {
}
}
-
-
-@Override
+
+ @Override
public String getMountPath() {
return mountPath;
}
- boolean isRoot(Path path) {
+ boolean isMountRoot(Path path) {
try {
- return isRoot && Files.isSameFile(rootPath, path);
+ return Files.isSameFile(rootPath, path);
} catch (IOException e) {
throw new ContentResourceException(e);
}
import java.nio.file.spi.FileSystemProvider;
import java.util.concurrent.Callable;
-import org.argeo.cms.acr.fs.SyncFileVisitor;
-import org.argeo.cms.acr.fs.SyncResult;
-
/** Synchronises two paths. */
public class PathSync implements Callable<SyncResult<Path>> {
private final URI sourceUri, targetUri;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
+/** Content persisted as a DOM element. */
public class DomContent extends AbstractContent implements ProvidedContent {
private final ProvidedSession session;
Object previous = get(key);
String namespaceUriOrNull = XMLConstants.NULL_NS_URI.equals(key.getNamespaceURI()) ? null
: key.getNamespaceURI();
+ String prefixToUse = registerPrefixIfNeeded(key);
element.setAttributeNS(namespaceUriOrNull,
- namespaceUriOrNull == null ? key.getLocalPart() : key.getPrefix() + ":" + key.getLocalPart(),
+ namespaceUriOrNull == null ? key.getLocalPart() : prefixToUse + ":" + key.getLocalPart(),
value.toString());
return previous;
}
+ protected String registerPrefixIfNeeded(QName name) {
+ String namespaceUriOrNull = XMLConstants.NULL_NS_URI.equals(name.getNamespaceURI()) ? null
+ : name.getNamespaceURI();
+ String prefixToUse;
+ if (namespaceUriOrNull != null) {
+ String registeredPrefix = provider.getPrefix(namespaceUriOrNull);
+ if (registeredPrefix != null) {
+ prefixToUse = registeredPrefix;
+ } else {
+ provider.registerPrefix(name.getPrefix(), namespaceUriOrNull);
+ prefixToUse = name.getPrefix();
+ }
+ } else {
+ prefixToUse = null;
+ }
+ return prefixToUse;
+ }
+
@Override
public boolean hasText() {
// return element instanceof Text;
Document document = this.element.getOwnerDocument();
String namespaceUriOrNull = XMLConstants.NULL_NS_URI.equals(name.getNamespaceURI()) ? null
: name.getNamespaceURI();
+ String prefixToUse = registerPrefixIfNeeded(name);
Element child = document.createElementNS(namespaceUriOrNull,
- namespaceUriOrNull == null ? name.getLocalPart() : name.getPrefix() + ":" + name.getLocalPart());
+ namespaceUriOrNull == null ? name.getLocalPart() : prefixToUse + ":" + name.getLocalPart());
element.appendChild(child);
return new DomContent(this, child);
}
}
+ @SuppressWarnings("unchecked")
@Override
public <A> A adapt(Class<A> clss) throws IllegalArgumentException {
if (CharBuffer.class.isAssignableFrom(clss)) {
return super.adapt(clss);
}
+ @SuppressWarnings("unchecked")
public <A> CompletableFuture<A> write(Class<A> clss) {
if (String.class.isAssignableFrom(clss)) {
CompletableFuture<String> res = new CompletableFuture<>();
return mountPath;
}
+ public void registerPrefix(String prefix, String namespace) {
+ DomUtils.addNamespace(document.getDocumentElement(), prefix, namespace);
+ }
+
/*
* NAMESPACE CONTEXT
*/
package org.argeo.cms.acr.xml;
-import java.io.IOException;
-import java.io.OutputStream;
-
import javax.xml.XMLConstants;
-import javax.xml.transform.OutputKeys;
-import javax.xml.transform.Transformer;
-import javax.xml.transform.TransformerException;
-import javax.xml.transform.TransformerFactory;
-import javax.xml.transform.dom.DOMSource;
-import javax.xml.transform.stream.StreamResult;
-import org.w3c.dom.Document;
import org.w3c.dom.Element;
public class DomUtils {