+++ /dev/null
-package org.argeo.api.gcr;
-
-import java.util.AbstractMap;
-import java.util.HashSet;
-import java.util.Set;
-
-public abstract class AbstractContent extends AbstractMap<String, Object> implements Content {
-
- @Override
- public Set<Entry<String, Object>> entrySet() {
- Set<Entry<String, Object>> result = new HashSet<>();
- for (String key : keys()) {
- Entry<String, Object> entry = new Entry<String, Object>() {
-
- @Override
- public String getKey() {
- return key;
- }
-
- @Override
- public Object getValue() {
- // TODO check type
- return get(key, Object.class);
- }
-
- @Override
- public Object setValue(Object value) {
- throw new UnsupportedOperationException();
- }
-
- };
- result.add(entry);
- }
- return result;
- }
-
- protected abstract Iterable<String> keys();
-}
--- /dev/null
+package org.argeo.api.gcr;
+
+/**
+ * An attribute type MUST consistently parse a string to an object so that
+ * <code>parse(obj.toString()).equals(obj)</code> is verified.
+ * {@link #format(Object)} can be overridden to provide more efficient
+ * implementations but the returned
+ * <code>String<code> MUST be the same, that is <code>format(obj).equals(obj.toString())</code>
+ * is verified.
+ */
+public interface AttributeFormatter<T> {
+ /** Parses a String to a Java object. */
+ T parse(String str) throws IllegalArgumentException;
+
+ /** Default implementation returns {@link Object#toString()} on the argument. */
+ default String format(T obj) {
+ return obj.toString();
+ }
+}
<A> A get(String key, Class<A> clss);
- ContentSession getSession();
+// ContentSession getSession();
/*
* DEFAULT METHODS
return get(key, String.class);
}
- default String attr(Enum<?> key) {
- return attr(key.name());
+ default String attr(Object key) {
+ return key != null ? attr(key.toString()) : attr(null);
}
- default <A> A get(Enum<?> key, Class<A> clss) {
- return get(key.name(), clss);
+ default <A> A get(Object key, Class<A> clss) {
+ return key != null ? get(key.toString(), clss) : get(null, clss);
}
/*
package org.argeo.api.gcr;
+import java.util.Locale;
import java.util.function.Supplier;
+/**
+ * A content repository is an actually running implementation of various kind of
+ * content system. It allows a pre-authenticated caller to open a session.
+ */
public interface ContentRepository extends Supplier<ContentSession> {
+ ContentSession get(Locale locale);
}
package org.argeo.api.gcr;
-import java.util.function.Supplier;
+import java.util.Locale;
-public interface ContentSession extends Supplier<Content> {
+import javax.security.auth.Subject;
+public interface ContentSession {
+ Subject getSubject();
+
+ Locale getLocale();
}
--- /dev/null
+package org.argeo.api.gcr;
+
+public interface ContentStore {
+
+}
--- /dev/null
+package org.argeo.api.gcr;
+
+public interface ContentSystem {
+
+}
--- /dev/null
+package org.argeo.api.gcr;
+
+import java.util.function.Supplier;
+
+public interface ContentSystemProvider extends Supplier<Content> {
+
+}
--- /dev/null
+package org.argeo.api.gcr;
+
+import java.io.PrintStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Arrays;
+import java.util.Base64;
+import java.util.List;
+import java.util.function.BiConsumer;
+
+public class ContentUtils {
+ public static void traverse(Content content, BiConsumer<Content, Integer> doIt) {
+ traverse(content, doIt, 0);
+ }
+
+ public static void traverse(Content content, BiConsumer<Content, Integer> doIt, int currentDepth) {
+ doIt.accept(content, currentDepth);
+ int nextDepth = currentDepth + 1;
+ for (Content child : content) {
+ traverse(child, doIt, nextDepth);
+ }
+ }
+
+ public static void print(Content content, PrintStream out, int depth, boolean printText) {
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < depth; i++) {
+ sb.append(" ");
+ }
+ String prefix = sb.toString();
+ out.println(prefix + content.getName());
+ for (String key : content.keySet()) {
+ out.println(prefix + " " + key + "=" + content.get(key));
+ }
+ if (printText) {
+ if (content.hasText()) {
+ out.println("<![CDATA[" + content.getText().trim() + "]]>");
+ }
+ }
+ }
+
+ public static URI bytesToDataURI(byte[] arr) {
+ String base64Str = Base64.getEncoder().encodeToString(arr);
+ try {
+ final String PREFIX = "data:application/octet-stream;base64,";
+ return new URI(PREFIX + base64Str);
+ } catch (URISyntaxException e) {
+ throw new IllegalStateException("Cannot serialize bytes a Base64 data URI", e);
+ }
+
+ }
+
+ public static byte[] bytesFromDataURI(URI uri) {
+ if (!"data".equals(uri.getScheme()))
+ throw new IllegalArgumentException("URI must have 'data' as a scheme");
+ String schemeSpecificPart = uri.getSchemeSpecificPart();
+ int commaIndex = schemeSpecificPart.indexOf(',');
+ String prefix = schemeSpecificPart.substring(0, commaIndex);
+ List<String> info = Arrays.asList(prefix.split(";"));
+ if (!info.contains("base64"))
+ throw new IllegalArgumentException("URI must specify base64");
+
+ String base64Str = uri.toString().substring(commaIndex);
+ return Base64.getDecoder().decode(base64Str);
+
+ }
+
+ public static <T> boolean isString(T t) {
+ return t instanceof String;
+ }
+
+ /** Singleton. */
+ private ContentUtils() {
+
+ }
+}
+++ /dev/null
-package org.argeo.api.gcr;
-
-import java.io.PrintStream;
-import java.util.function.BiConsumer;
-
-public class Contents {
- public static void traverse(Content content, BiConsumer<Content, Integer> doIt) {
- traverse(content, doIt, 0);
- }
-
- public static void traverse(Content content, BiConsumer<Content, Integer> doIt, int currentDepth) {
- doIt.accept(content, currentDepth);
- int nextDepth = currentDepth + 1;
- for (Content child : content) {
- traverse(child, doIt, nextDepth);
- }
- }
-
- public static void print(Content content, PrintStream out, int depth, boolean printText) {
- StringBuilder sb = new StringBuilder();
- for (int i = 0; i < depth; i++) {
- sb.append(" ");
- }
- String prefix = sb.toString();
- out.println(prefix + content.getName());
- for (String key : content.keySet()) {
- out.println(prefix + " " + key + "=" + content.get(key));
- }
- if (printText) {
- if (content.hasText()) {
- out.println("<![CDATA[" + content.getText().trim() + "]]>");
- }
- }
- }
-
- public static <T> boolean isString(T t) {
- return t instanceof String;
- }
-
- /** Singleton. */
- private Contents() {
-
- }
-}
--- /dev/null
+package org.argeo.api.gcr;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.time.Instant;
+import java.time.format.DateTimeParseException;
+import java.util.UUID;
+
+/**
+ * Minimal standard attribute types that MUST be supported. All related classes
+ * belong to java.base and can be implicitly derived form a given
+ * <code>String<code>.
+ */
+public enum StandardAttributeType {
+ BOOLEAN(Boolean.class, new BooleanFormatter()), //
+ // TODO Also support INTEGER ?
+ LONG(Long.class, new LongFormatter()), //
+ DOUBLE(Double.class, new DoubleFormatter()), //
+ INSTANT(Instant.class, new InstantFormatter()), //
+ UUID(UUID.class, new UuidFormatter()), //
+ URI(URI.class, new UriFormatter()), //
+ STRING(String.class, new StringFormatter()), //
+ ;
+
+ private <T> StandardAttributeType(Class<T> clss, AttributeFormatter<T> formatter) {
+ this.clss = clss;
+ this.formatter = formatter;
+ }
+
+ private final Class<?> clss;
+ private final AttributeFormatter<?> formatter;
+
+ public Class<?> getClss() {
+ return clss;
+ }
+
+ public AttributeFormatter<?> getFormatter() {
+ return formatter;
+ }
+
+ static Object parse(String str) {
+ if (str == null)
+ return null;
+ // order IS important
+ try {
+ if (str.length() == 4 || str.length() == 5)
+ return BOOLEAN.getFormatter().parse(str);
+ } catch (IllegalArgumentException e) {
+ // silent
+ }
+ try {
+ return LONG.getFormatter().parse(str);
+ } catch (IllegalArgumentException e) {
+ // silent
+ }
+ try {
+ return DOUBLE.getFormatter().parse(str);
+ } catch (IllegalArgumentException e) {
+ // silent
+ }
+ try {
+ return INSTANT.getFormatter().parse(str);
+ } catch (IllegalArgumentException e) {
+ // silent
+ }
+ try {
+ if (str.length() == 36)
+ return UUID.getFormatter().parse(str);
+ } catch (IllegalArgumentException e) {
+ // silent
+ }
+ try {
+ java.net.URI uri = (java.net.URI) URI.getFormatter().parse(str);
+ if (uri.getScheme() != null)
+ return uri;
+ String path = uri.getPath();
+ if (path.indexOf('/') >= 0)
+ return uri;
+ // if it is not clearly a path, we will consider it as a string
+ // because their is no way to distinguish between 'any_string'
+ // and 'any_file_name'.
+ // Note that providing ./any_file_name would result in an equivalent URI
+ } catch (IllegalArgumentException e) {
+ // silent
+ }
+
+ // default
+ return STRING.getFormatter().parse(str);
+ }
+
+ static class StringFormatter implements AttributeFormatter<String> {
+
+ @Override
+ public String parse(String str) {
+ return str;
+ }
+
+ @Override
+ public String format(String obj) {
+ return obj;
+ }
+
+ }
+
+ static class BooleanFormatter implements AttributeFormatter<Boolean> {
+
+ /**
+ * @param str must be exactly equals to either 'true' or 'false' (different
+ * contract than {@link Boolean#parseBoolean(String)}.
+ */
+ @Override
+ public Boolean parse(String str) throws IllegalArgumentException {
+ if ("true".equals(str))
+ return Boolean.TRUE;
+ if ("false".equals(str))
+ return Boolean.FALSE;
+ throw new IllegalArgumentException("Argument is neither 'true' or 'false' : " + str);
+ }
+ }
+
+ static class LongFormatter implements AttributeFormatter<Long> {
+ @Override
+ public Long parse(String str) throws NumberFormatException {
+ return Long.parseLong(str);
+ }
+ }
+
+ static class DoubleFormatter implements AttributeFormatter<Double> {
+
+ @Override
+ public Double parse(String str) throws NumberFormatException {
+ return Double.parseDouble(str);
+ }
+ }
+
+ static class InstantFormatter implements AttributeFormatter<Instant> {
+
+ @Override
+ public Instant parse(String str) throws IllegalArgumentException {
+ try {
+ return Instant.parse(str);
+ } catch (DateTimeParseException e) {
+ throw new IllegalArgumentException("Cannot parse '" + str + "' as an instant", e);
+ }
+ }
+ }
+
+ static class UuidFormatter implements AttributeFormatter<UUID> {
+
+ @Override
+ public UUID parse(String str) throws IllegalArgumentException {
+ return java.util.UUID.fromString(str);
+ }
+ }
+
+ static class UriFormatter implements AttributeFormatter<URI> {
+
+ @Override
+ public URI parse(String str) throws IllegalArgumentException {
+ try {
+ return new URI(str);
+ } catch (URISyntaxException e) {
+ throw new IllegalArgumentException("Cannot parse " + str + " as an URI.", e);
+ }
+ }
+
+ }
+}
--- /dev/null
+package org.argeo.api.gcr.fs;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.nio.file.LinkOption;
+import java.nio.file.Path;
+import java.nio.file.WatchEvent.Kind;
+import java.nio.file.WatchEvent.Modifier;
+import java.nio.file.WatchKey;
+import java.nio.file.WatchService;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+public abstract class AbstractFsPath<FS extends AbstractFsSystem<ST>, ST extends AbstractFsStore> implements Path {
+ private final FS fs;
+ /** null for non absolute paths */
+ private final ST fileStore;
+
+ private final String[] segments;// null means root
+ private final boolean absolute;
+
+ private final String separator;
+
+ // optim
+ private final int hashCode;
+
+ public AbstractFsPath(FS filesSystem, String path) {
+ if (path == null)
+ throw new IllegalArgumentException("Path cannot be null");
+ this.fs = filesSystem;
+ this.separator = fs.getSeparator();
+ // TODO deal with both path and separator being empty strings
+ if (path.equals(separator)) {// root
+ this.segments = null;
+ this.absolute = true;
+ this.hashCode = 0;
+ this.fileStore = fs.getBaseFileStore();
+ return;
+ } else if (path.equals("")) {// empty path
+ this.segments = new String[] { "" };
+ this.absolute = false;
+ this.hashCode = "".hashCode();
+ this.fileStore = null;
+ return;
+ }
+
+ this.absolute = path.startsWith(toStringRoot());
+
+ String trimmedPath = path.substring(absolute ? toStringRoot().length() : 0,
+ path.endsWith(separator) ? path.length() - separator.length() : path.length());
+ this.segments = trimmedPath.split(separator);
+ // clean up
+ for (int i = 0; i < this.segments.length; i++) {
+ this.segments[i] = cleanUpSegment(this.segments[i]);
+ }
+ this.hashCode = this.segments[this.segments.length - 1].hashCode();
+
+ this.fileStore = isAbsolute() ? fs.getFileStore(path) : null;
+ }
+
+ protected AbstractFsPath(FS filesSystem, ST fileStore, String[] segments, boolean absolute) {
+ this.segments = segments;
+ this.absolute = absolute;
+ this.hashCode = segments == null ? 0 : segments[segments.length - 1].hashCode();
+ this.separator = filesSystem.getSeparator();
+// super(path, path == null ? true : absolute, filesSystem.getSeparator());
+// assert path == null ? absolute == true : true;
+ this.fs = filesSystem;
+// this.path = path;
+// this.absolute = path == null ? true : absolute;
+ if (isAbsolute() && fileStore == null)
+ throw new IllegalArgumentException("Absolute path requires a file store");
+ if (!isAbsolute() && fileStore != null)
+ throw new IllegalArgumentException("A file store should not be provided for a relative path");
+ this.fileStore = fileStore;
+ assert !(absolute && fileStore == null);
+ }
+
+ protected Path retrieve(String path) {
+ return getFileSystem().getPath(path);
+ }
+
+ @Override
+ public FS getFileSystem() {
+ return fs;
+ }
+
+ public ST getFileStore() {
+ return fileStore;
+ }
+
+ @Override
+ public boolean isAbsolute() {
+ return absolute;
+ }
+
+ @Override
+ public URI toUri() {
+ try {
+ return new URI(fs.provider().getScheme(), toString(), null);
+ } catch (URISyntaxException e) {
+ throw new IllegalStateException("Cannot create URI for " + toString(), e);
+ }
+ }
+
+ @Override
+ public Path toAbsolutePath() {
+ if (isAbsolute())
+ return this;
+ // FIXME it doesn't seem right
+ return newInstance(getSegments(), true);
+ }
+
+ @Override
+ public Path toRealPath(LinkOption... options) throws IOException {
+ return this;
+ }
+
+ @Override
+ public File toFile() {
+ throw new UnsupportedOperationException();
+ }
+
+ /*
+ * PATH OPERATIONS
+ */
+ public final Path resolveSibling(Path other) {
+ if (other == null)
+ throw new NullPointerException();
+ Path parent = getParent();
+ return (parent == null) ? other : parent.resolve(other);
+ }
+
+ @Override
+ public final Path resolveSibling(String other) {
+ return resolveSibling(getFileSystem().getPath(other));
+ }
+
+ public final Path resolve(String other) {
+ return resolve(retrieve(other));
+ }
+
+ public boolean startsWith(Path other) {
+ return toString().startsWith(other.toString());
+ }
+
+ public boolean endsWith(Path other) {
+ return toString().endsWith(other.toString());
+ }
+
+ @Override
+ public Path normalize() {
+ // always normalized
+ return this;
+ }
+
+ @Override
+ public final Iterator<Path> iterator() {
+ return new Iterator<Path>() {
+ private int i = 0;
+
+ @Override
+ public boolean hasNext() {
+ return (i < getNameCount());
+ }
+
+ @Override
+ public Path next() {
+ if (i < getNameCount()) {
+ Path result = getName(i);
+ i++;
+ return result;
+ } else {
+ throw new NoSuchElementException();
+ }
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+
+ @Override
+ public int compareTo(Path other) {
+ return toString().compareTo(other.toString());
+ }
+
+ public Path resolve(Path other) {
+ AbstractFsPath<?, ?> otherPath = (AbstractFsPath<?, ?>) other;
+ if (otherPath.isAbsolute())
+ return other;
+ String[] newPath;
+ if (isRoot()) {
+ newPath = new String[otherPath.segments.length];
+ System.arraycopy(otherPath.segments, 0, newPath, 0, otherPath.segments.length);
+ } else {
+ newPath = new String[segments.length + otherPath.segments.length];
+ System.arraycopy(segments, 0, newPath, 0, segments.length);
+ System.arraycopy(otherPath.segments, 0, newPath, segments.length, otherPath.segments.length);
+ }
+ if (!absolute)
+ return newInstance(newPath, absolute);
+ else {
+ return newInstance(toString(newPath));
+ }
+ }
+
+ public Path relativize(Path other) {
+ if (equals(other))
+ return newInstance("");
+ if (other.toString().startsWith(this.toString())) {
+ String p1 = toString();
+ String p2 = other.toString();
+ String relative = p2.substring(p1.length(), p2.length());
+ if (relative.charAt(0) == '/')
+ relative = relative.substring(1);
+ return newInstance(relative);
+ }
+ throw new IllegalArgumentException(other + " cannot be relativized against " + this);
+ }
+
+ /*
+ * FACTORIES
+ */
+ protected abstract AbstractFsPath<FS, ST> newInstance(String path);
+
+ protected abstract AbstractFsPath<FS, ST> newInstance(String[] segments, boolean absolute);
+
+ /*
+ * CUSTOMISATIONS
+ */
+ protected String toStringRoot() {
+ return separator;
+ }
+
+ protected String cleanUpSegment(String segment) {
+ return segment;
+ }
+
+ protected boolean isRoot() {
+ return segments == null;
+ }
+
+ protected boolean isEmpty() {
+ return segments.length == 1 && "".equals(segments[0]);
+ }
+
+ /*
+ * PATH OPERATIONS
+ */
+ public AbstractFsPath<FS, ST> getRoot() {
+ return newInstance(toStringRoot());
+ }
+
+ public AbstractFsPath<FS, ST> getParent() {
+ if (isRoot())
+ return null;
+ // FIXME empty path?
+ if (segments.length == 1)// first level
+ return newInstance(toStringRoot());
+ String[] parentPath = Arrays.copyOfRange(segments, 0, segments.length - 1);
+ if (!absolute)
+ return newInstance(parentPath, absolute);
+ else
+ return newInstance(toString(parentPath));
+ }
+
+ public AbstractFsPath<FS, ST> getFileName() {
+ if (isRoot())
+ return null;
+ return newInstance(segments[segments.length - 1]);
+ }
+
+ public int getNameCount() {
+ if (isRoot())
+ return 0;
+ return segments.length;
+ }
+
+ public AbstractFsPath<FS, ST> getName(int index) {
+ if (isRoot())
+ return null;
+ return newInstance(segments[index]);
+ }
+
+ public AbstractFsPath<FS, ST> subpath(int beginIndex, int endIndex) {
+ if (isRoot())
+ return null;
+ String[] parentPath = Arrays.copyOfRange(segments, beginIndex, endIndex);
+ return newInstance(parentPath, false);
+ }
+
+ public boolean startsWith(String other) {
+ return toString().startsWith(other);
+ }
+
+ public boolean endsWith(String other) {
+ return toString().endsWith(other);
+ }
+
+ /*
+ * UTILITIES
+ */
+ protected String toString(String[] path) {
+ if (isRoot())
+ return toStringRoot();
+ StringBuilder sb = new StringBuilder();
+ if (isAbsolute())
+ sb.append(separator);
+ for (int i = 0; i < path.length; i++) {
+ if (i != 0)
+ sb.append(separator);
+ sb.append(path[i]);
+ }
+ return sb.toString();
+ }
+
+ @Override
+ public String toString() {
+ return toString(segments);
+ }
+
+ @Override
+ public int hashCode() {
+ return hashCode;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof AbstractFsPath))
+ return false;
+ AbstractFsPath<?, ?> other = (AbstractFsPath<?, ?>) obj;
+
+ if (isRoot()) {// root
+ if (other.isRoot())// root
+ return true;
+ else
+ return false;
+ } else {
+ if (other.isRoot())// root
+ return false;
+ }
+ // non root
+ if (segments.length != other.segments.length)
+ return false;
+ for (int i = 0; i < segments.length; i++) {
+ if (!segments[i].equals(other.segments[i]))
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ protected Object clone() throws CloneNotSupportedException {
+ return newInstance(toString());
+ }
+
+ /*
+ * GETTERS / SETTERS
+ */
+ protected String[] getSegments() {
+ return segments;
+ }
+
+ protected String getSeparator() {
+ return separator;
+ }
+
+ /*
+ * UNSUPPORTED
+ */
+ @Override
+ public WatchKey register(WatchService watcher, Kind<?>[] events, Modifier... modifiers) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public WatchKey register(WatchService watcher, Kind<?>... events) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+}
--- /dev/null
+package org.argeo.api.gcr.fs;
+
+import java.nio.file.FileStore;
+
+public abstract class AbstractFsStore extends FileStore {
+
+}
--- /dev/null
+package org.argeo.api.gcr.fs;
+
+import java.nio.file.FileSystem;
+
+public abstract class AbstractFsSystem<ST extends AbstractFsStore> extends FileSystem {
+ public abstract ST getBaseFileStore();
+
+ public abstract ST getFileStore(String path);
+}
--- /dev/null
+package org.argeo.api.gcr.spi;
+
+import java.util.AbstractMap;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.argeo.api.gcr.Content;
+
+public abstract class AbstractContent extends AbstractMap<String, Object> implements Content {
+
+ @Override
+ public Set<Entry<String, Object>> entrySet() {
+ Set<Entry<String, Object>> result = new HashSet<>();
+ for (String key : keys()) {
+ Entry<String, Object> entry = new Entry<String, Object>() {
+
+ @Override
+ public String getKey() {
+ return key;
+ }
+
+ @Override
+ public Object getValue() {
+ // TODO check type
+ return get(key, Object.class);
+ }
+
+ @Override
+ public Object setValue(Object value) {
+ throw new UnsupportedOperationException();
+ }
+
+ };
+ result.add(entry);
+ }
+ return result;
+ }
+
+ protected abstract Iterable<String> keys();
+
+ /*
+ * UTILITIES
+ */
+ protected boolean isDefaultAttrTypeRequested(Class<?> clss) {
+ // check whether clss is Object.class
+ return clss.isAssignableFrom(Object.class);
+ }
+}
--- /dev/null
+package org.argeo.cms.jcr.gcr;
+
+import java.util.Calendar;
+import java.util.Iterator;
+
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.Property;
+import javax.jcr.PropertyIterator;
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+
+import org.argeo.api.gcr.Content;
+import org.argeo.api.gcr.spi.AbstractContent;
+import org.argeo.jcr.Jcr;
+import org.argeo.jcr.JcrException;
+
+public class JcrContent extends AbstractContent {
+ private JcrContentSession contentSession;
+ private Node jcrNode;
+
+ protected JcrContent(JcrContentSession contentSession, Node node) {
+ this.contentSession = contentSession;
+ this.jcrNode = node;
+ }
+
+ @Override
+ public String getName() {
+ return Jcr.getName(jcrNode);
+ }
+
+ @Override
+ public <A> A get(String key, Class<A> clss) {
+ if (isDefaultAttrTypeRequested(clss)) {
+ return (A) get(jcrNode, key);
+ }
+ return (A) Jcr.get(jcrNode, key);
+ }
+
+ @Override
+ public Iterator<Content> iterator() {
+ try {
+ return new JcrContentIterator(contentSession, jcrNode.getNodes());
+ } catch (RepositoryException e) {
+ throw new JcrException("Cannot list children of " + jcrNode, e);
+ }
+ }
+
+ @Override
+ protected Iterable<String> keys() {
+ return new Iterable<String>() {
+
+ @Override
+ public Iterator<String> iterator() {
+ try {
+ PropertyIterator propertyIterator = jcrNode.getProperties();
+ return new JcrKeyIterator(contentSession, propertyIterator);
+ } catch (RepositoryException e) {
+ throw new JcrException("Cannot retrive properties from " + jcrNode, e);
+ }
+ }
+ };
+ }
+
+ public Node getJcrNode() {
+ return jcrNode;
+ }
+
+ /** Cast to a standard Java object. */
+ static Object get(Node node, String property) {
+ try {
+ Value value = node.getProperty(property).getValue();
+ switch (value.getType()) {
+ case PropertyType.STRING:
+ return value.getString();
+ case PropertyType.DOUBLE:
+ return (Double) value.getDouble();
+ case PropertyType.LONG:
+ return (Long) value.getLong();
+ case PropertyType.BOOLEAN:
+ return (Boolean) value.getBoolean();
+ case PropertyType.DATE:
+ Calendar calendar = value.getDate();
+ return calendar.toInstant();
+ case PropertyType.BINARY:
+ throw new IllegalArgumentException("Binary is not supported as an attribute");
+ default:
+ return value.getString();
+ }
+ } catch (RepositoryException e) {
+ throw new JcrException("Cannot cast value from " + property + " of node " + node, e);
+ }
+ }
+
+ static class JcrContentIterator implements Iterator<Content> {
+ private final JcrContentSession contentSession;
+ private final NodeIterator nodeIterator;
+ // we keep track in order to be able to delete it
+ private JcrContent current = null;
+
+ protected JcrContentIterator(JcrContentSession contentSession, NodeIterator nodeIterator) {
+ this.contentSession = contentSession;
+ this.nodeIterator = nodeIterator;
+ }
+
+ @Override
+ public boolean hasNext() {
+ return nodeIterator.hasNext();
+ }
+
+ @Override
+ public Content next() {
+ current = new JcrContent(contentSession, nodeIterator.nextNode());
+ return current;
+ }
+
+ @Override
+ public void remove() {
+ if (current != null) {
+ // current.getJcrNode().remove();
+ }
+ throw new UnsupportedOperationException();
+ }
+
+ }
+
+ static class JcrKeyIterator implements Iterator<String> {
+ private final JcrContentSession contentSession;
+ private final PropertyIterator propertyIterator;
+
+ protected JcrKeyIterator(JcrContentSession contentSession, PropertyIterator propertyIterator) {
+ this.contentSession = contentSession;
+ this.propertyIterator = propertyIterator;
+ }
+
+ @Override
+ public boolean hasNext() {
+ return propertyIterator.hasNext();
+ }
+
+ @Override
+ public String next() {
+ Property property = null;
+ try {
+ property = propertyIterator.nextProperty();
+ // TODO map standard property names
+ return property.getName();
+ } catch (RepositoryException e) {
+ throw new JcrException("Cannot retrieve property " + property, null);
+ }
+ }
+
+ }
+}
--- /dev/null
+package org.argeo.cms.jcr.gcr;
+
+import java.security.AccessController;
+import java.util.Locale;
+
+import javax.jcr.Repository;
+import javax.security.auth.Subject;
+
+import org.argeo.api.gcr.ContentRepository;
+import org.argeo.api.gcr.ContentSession;
+
+public class JcrContentRepository implements ContentRepository {
+ private Repository jcrRepository;
+
+ @Override
+ public ContentSession get() {
+ // TODO retrieve locale from Subject?
+ return get(Locale.getDefault());
+ }
+
+ @Override
+ public ContentSession get(Locale locale) {
+ Subject subject = Subject.getSubject(AccessController.getContext());
+ return new JcrContentSession(jcrRepository, subject, locale);
+ }
+
+ public Repository getJcrRepository() {
+ return jcrRepository;
+ }
+
+ public void setJcrRepository(Repository jcrRepository) {
+ this.jcrRepository = jcrRepository;
+ }
+
+}
--- /dev/null
+package org.argeo.cms.jcr.gcr;
+
+import java.security.PrivilegedAction;
+import java.util.Locale;
+
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.security.auth.Subject;
+
+import org.argeo.api.gcr.ContentSession;
+import org.argeo.jcr.JcrException;
+
+public class JcrContentSession implements ContentSession {
+ private Repository jcrRepository;
+ private Subject subject;
+ private Locale locale;
+ private Session jcrSession;
+
+ protected JcrContentSession(Repository jcrRepository, Subject subject, Locale locale) {
+ this.jcrRepository = jcrRepository;
+ this.subject = subject;
+ this.locale = locale;
+ this.jcrSession = Subject.doAs(this.subject, (PrivilegedAction<Session>) () -> {
+ try {
+ return jcrRepository.login();
+ } catch (RepositoryException e) {
+ throw new JcrException("Cannot log in to repository", e);
+ }
+ });
+ }
+
+ @Override
+ public Subject getSubject() {
+ return subject;
+ }
+
+ @Override
+ public Locale getLocale() {
+ return locale;
+ }
+
+ public Session getJcrSession() {
+ return jcrSession;
+ }
+
+}
throw new JcrException("Cannot retrieve property " + property + " from " + node, e);
}
}
+
+ public static <T> T getAs(Node node, String property, Class<T> clss) {
+ if(String.class.isAssignableFrom(clss)) {
+ return (T)get(node,property);
+ } else if(Long.class.isAssignableFrom(clss)) {
+ return (T)get(node,property);
+ }else {
+ throw new IllegalArgumentException("Unsupported format "+clss);
+ }
+ }
/**
* Get a multiple property as a list, doing a best effort to cast it as the
import javax.jcr.Session;
import javax.jcr.nodetype.NodeType;
+import org.argeo.api.gcr.fs.AbstractFsStore;
+import org.argeo.api.gcr.fs.AbstractFsSystem;
import org.argeo.jcr.Jcr;
import org.argeo.jcr.JcrUtils;
-public class JcrFileSystem extends FileSystem {
+public class JcrFileSystem extends AbstractFsSystem<WorkspaceFileStore> {
private final JcrFileSystemProvider provider;
private final Repository repository;
package org.argeo.jcr.fs;
-import java.io.File;
-import java.io.IOException;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.nio.file.FileSystem;
-import java.nio.file.LinkOption;
import java.nio.file.Path;
-import java.nio.file.WatchEvent.Kind;
-import java.nio.file.WatchEvent.Modifier;
-import java.nio.file.WatchKey;
-import java.nio.file.WatchService;
-import java.util.Arrays;
-import java.util.Iterator;
-import java.util.NoSuchElementException;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
+import org.argeo.api.gcr.fs.AbstractFsPath;
+
/** A {@link Path} which contains a reference to a JCR {@link Node}. */
-public class JcrPath implements Path {
+public class JcrPath extends AbstractFsPath<JcrFileSystem, WorkspaceFileStore> {
final static String separator = "/";
final static char separatorChar = '/';
- private final JcrFileSystem fs;
- /** null for non absolute paths */
- private final WorkspaceFileStore fileStore;
- private final String[] path;// null means root
- private final boolean absolute;
-
- // optim
- private final int hashCode;
+// private final JcrFileSystem fs;
+// /** null for non absolute paths */
+// private final WorkspaceFileStore fileStore;
+// private final String[] path;// null means root
+// private final boolean absolute;
+//
+// // optim
+// private final int hashCode;
public JcrPath(JcrFileSystem filesSystem, String path) {
- this.fs = filesSystem;
- if (path == null)
- throw new JcrFsException("Path cannot be null");
- if (path.equals(separator)) {// root
- this.path = null;
- this.absolute = true;
- this.hashCode = 0;
- this.fileStore = fs.getBaseFileStore();
- return;
- } else if (path.equals("")) {// empty path
- this.path = new String[] { "" };
- this.absolute = false;
- this.fileStore = null;
- this.hashCode = "".hashCode();
- return;
- }
-
- if (path.equals("~")) {// home
- path = filesSystem.getUserHomePath();
- if (path == null)
- throw new JcrFsException("No home directory available");
- }
-
- this.absolute = path.charAt(0) == separatorChar ? true : false;
-
- this.fileStore = absolute ? fs.getFileStore(path) : null;
-
- String trimmedPath = path.substring(absolute ? 1 : 0,
- path.charAt(path.length() - 1) == separatorChar ? path.length() - 1 : path.length());
- this.path = trimmedPath.split(separator);
- for (int i = 0; i < this.path.length; i++) {
- this.path[i] = Text.unescapeIllegalJcrChars(this.path[i]);
- }
- this.hashCode = this.path[this.path.length - 1].hashCode();
- assert !(absolute && fileStore == null);
+ super(filesSystem, path);
+// this.fs = filesSystem;
+// if (path == null)
+// throw new JcrFsException("Path cannot be null");
+// if (path.equals(separator)) {// root
+// this.path = null;
+// this.absolute = true;
+// this.hashCode = 0;
+// this.fileStore = fs.getBaseFileStore();
+// return;
+// } else if (path.equals("")) {// empty path
+// this.path = new String[] { "" };
+// this.absolute = false;
+// this.fileStore = null;
+// this.hashCode = "".hashCode();
+// return;
+// }
+//
+// if (path.equals("~")) {// home
+// path = filesSystem.getUserHomePath();
+// if (path == null)
+// throw new JcrFsException("No home directory available");
+// }
+//
+// this.absolute = path.charAt(0) == separatorChar ? true : false;
+//
+// this.fileStore = absolute ? fs.getFileStore(path) : null;
+//
+// String trimmedPath = path.substring(absolute ? 1 : 0,
+// path.charAt(path.length() - 1) == separatorChar ? path.length() - 1 : path.length());
+// this.path = trimmedPath.split(separator);
+// for (int i = 0; i < this.path.length; i++) {
+// this.path[i] = Text.unescapeIllegalJcrChars(this.path[i]);
+// }
+// this.hashCode = this.path[this.path.length - 1].hashCode();
+// assert !(absolute && fileStore == null);
}
public JcrPath(JcrFileSystem filesSystem, Node node) throws RepositoryException {
/** Internal optimisation */
private JcrPath(JcrFileSystem filesSystem, WorkspaceFileStore fileStore, String[] path, boolean absolute) {
- this.fs = filesSystem;
- this.path = path;
- this.absolute = path == null ? true : absolute;
- if (this.absolute && fileStore == null)
- throw new IllegalArgumentException("Absolute path requires a file store");
- if (!this.absolute && fileStore != null)
- throw new IllegalArgumentException("A file store should not be provided for a relative path");
- this.fileStore = fileStore;
- this.hashCode = path == null ? 0 : path[path.length - 1].hashCode();
- assert !(absolute && fileStore == null);
+ super(filesSystem, fileStore, path, absolute);
+// this.fs = filesSystem;
+// this.path = path;
+// this.absolute = path == null ? true : absolute;
+// if (this.absolute && fileStore == null)
+// throw new IllegalArgumentException("Absolute path requires a file store");
+// if (!this.absolute && fileStore != null)
+// throw new IllegalArgumentException("A file store should not be provided for a relative path");
+// this.fileStore = fileStore;
+// this.hashCode = path == null ? 0 : path[path.length - 1].hashCode();
+// assert !(absolute && fileStore == null);
}
- @Override
- public FileSystem getFileSystem() {
- return fs;
+ protected String cleanUpSegment(String segment) {
+ return Text.unescapeIllegalJcrChars(segment);
}
@Override
- public boolean isAbsolute() {
- return absolute;
+ protected JcrPath newInstance(String path) {
+ return new JcrPath(getFileSystem(), path);
}
@Override
- public Path getRoot() {
- if (path == null)
- return this;
- return new JcrPath(fs, separator);
- }
+ protected JcrPath newInstance(String[] segments, boolean absolute) {
+ return new JcrPath(getFileSystem(), getFileStore(), segments, absolute);
- @Override
- public String toString() {
- return toFsPath(path);
}
- private String toFsPath(String[] path) {
- if (path == null)
- return "/";
- StringBuilder sb = new StringBuilder();
- if (isAbsolute())
- sb.append('/');
- for (int i = 0; i < path.length; i++) {
- if (i != 0)
- sb.append('/');
- sb.append(path[i]);
- }
- return sb.toString();
- }
+// @Override
+// public FileSystem getFileSystem() {
+// return fs;
+// }
+//
+// @Override
+// public boolean isAbsolute() {
+// return absolute;
+// }
+//
+// @Override
+// public Path getRoot() {
+// if (path == null)
+// return this;
+// return new JcrPath(fs, separator);
+// }
+//
+// @Override
+// public String toString() {
+// return toFsPath(path);
+// }
+//
+// private String toFsPath(String[] path) {
+// if (path == null)
+// return "/";
+// StringBuilder sb = new StringBuilder();
+// if (isAbsolute())
+// sb.append('/');
+// for (int i = 0; i < path.length; i++) {
+// if (i != 0)
+// sb.append('/');
+// sb.append(path[i]);
+// }
+// return sb.toString();
+// }
// @Deprecated
// private String toJcrPath() {
// return sb.toString();
// }
- @Override
- public Path getFileName() {
- if (path == null)
- return null;
- return new JcrPath(fs, path[path.length - 1]);
- }
-
- @Override
- public Path getParent() {
- if (path == null)
- return null;
- if (path.length == 1)// root
- return new JcrPath(fs, separator);
- String[] parentPath = Arrays.copyOfRange(path, 0, path.length - 1);
- if (!absolute)
- return new JcrPath(fs, null, parentPath, absolute);
- else
- return new JcrPath(fs, toFsPath(parentPath));
- }
-
- @Override
- public int getNameCount() {
- if (path == null)
- return 0;
- return path.length;
- }
-
- @Override
- public Path getName(int index) {
- if (path == null)
- return null;
- return new JcrPath(fs, path[index]);
- }
-
- @Override
- public Path subpath(int beginIndex, int endIndex) {
- if (path == null)
- return null;
- String[] parentPath = Arrays.copyOfRange(path, beginIndex, endIndex);
- return new JcrPath(fs, null, parentPath, false);
- }
-
- @Override
- public boolean startsWith(Path other) {
- return toString().startsWith(other.toString());
- }
-
- @Override
- public boolean startsWith(String other) {
- return toString().startsWith(other);
- }
-
- @Override
- public boolean endsWith(Path other) {
- return toString().endsWith(other.toString());
- }
-
- @Override
- public boolean endsWith(String other) {
- return toString().endsWith(other);
- }
-
- @Override
- public Path normalize() {
- // always normalized
- return this;
- }
-
- @Override
- public Path resolve(Path other) {
- JcrPath otherPath = (JcrPath) other;
- if (otherPath.isAbsolute())
- return other;
- String[] newPath;
- if (path == null) {
- newPath = new String[otherPath.path.length];
- System.arraycopy(otherPath.path, 0, newPath, 0, otherPath.path.length);
- } else {
- newPath = new String[path.length + otherPath.path.length];
- System.arraycopy(path, 0, newPath, 0, path.length);
- System.arraycopy(otherPath.path, 0, newPath, path.length, otherPath.path.length);
- }
- if (!absolute)
- return new JcrPath(fs, null, newPath, absolute);
- else {
- return new JcrPath(fs, toFsPath(newPath));
- }
- }
-
- @Override
- public final Path resolve(String other) {
- return resolve(getFileSystem().getPath(other));
- }
-
- @Override
- public final Path resolveSibling(Path other) {
- if (other == null)
- throw new NullPointerException();
- Path parent = getParent();
- return (parent == null) ? other : parent.resolve(other);
- }
-
- @Override
- public final Path resolveSibling(String other) {
- return resolveSibling(getFileSystem().getPath(other));
- }
-
- @Override
- public final Iterator<Path> iterator() {
- return new Iterator<Path>() {
- private int i = 0;
-
- @Override
- public boolean hasNext() {
- return (i < getNameCount());
- }
-
- @Override
- public Path next() {
- if (i < getNameCount()) {
- Path result = getName(i);
- i++;
- return result;
- } else {
- throw new NoSuchElementException();
- }
- }
-
- @Override
- public void remove() {
- throw new UnsupportedOperationException();
- }
- };
- }
-
- @Override
- public Path relativize(Path other) {
- if (equals(other))
- return new JcrPath(fs, "");
- if (other.startsWith(this)) {
- String p1 = toString();
- String p2 = other.toString();
- String relative = p2.substring(p1.length(), p2.length());
- if (relative.charAt(0) == '/')
- relative = relative.substring(1);
- return new JcrPath(fs, relative);
- }
- throw new IllegalArgumentException(other + " cannot be relativized against " + this);
- }
-
- @Override
- public URI toUri() {
- try {
- return new URI(fs.provider().getScheme(), toString(), null);
- } catch (URISyntaxException e) {
- throw new JcrFsException("Cannot create URI for " + toString(), e);
- }
- }
-
- @Override
- public Path toAbsolutePath() {
- if (isAbsolute())
- return this;
- return new JcrPath(fs, fileStore, path, true);
- }
-
- @Override
- public Path toRealPath(LinkOption... options) throws IOException {
- return this;
- }
-
- @Override
- public File toFile() {
- throw new UnsupportedOperationException();
- }
+// @Override
+// public Path getFileName() {
+// if (path == null)
+// return null;
+// return new JcrPath(fs, path[path.length - 1]);
+// }
+//
+// @Override
+// public Path getParent() {
+// if (path == null)
+// return null;
+// if (path.length == 1)// root
+// return new JcrPath(fs, separator);
+// String[] parentPath = Arrays.copyOfRange(path, 0, path.length - 1);
+// if (!absolute)
+// return new JcrPath(fs, null, parentPath, absolute);
+// else
+// return new JcrPath(fs, toFsPath(parentPath));
+// }
+//
+// @Override
+// public int getNameCount() {
+// if (path == null)
+// return 0;
+// return path.length;
+// }
+//
+// @Override
+// public Path getName(int index) {
+// if (path == null)
+// return null;
+// return new JcrPath(fs, path[index]);
+// }
+//
+// @Override
+// public Path subpath(int beginIndex, int endIndex) {
+// if (path == null)
+// return null;
+// String[] parentPath = Arrays.copyOfRange(path, beginIndex, endIndex);
+// return new JcrPath(fs, null, parentPath, false);
+// }
+//
+// @Override
+// public boolean startsWith(Path other) {
+// return toString().startsWith(other.toString());
+// }
+//
+// @Override
+// public boolean startsWith(String other) {
+// return toString().startsWith(other);
+// }
+//
+// @Override
+// public boolean endsWith(Path other) {
+// return toString().endsWith(other.toString());
+// }
+//
+// @Override
+// public boolean endsWith(String other) {
+// return toString().endsWith(other);
+// }
- @Override
- public WatchKey register(WatchService watcher, Kind<?>[] events, Modifier... modifiers) throws IOException {
- // TODO Auto-generated method stub
- return null;
- }
+// @Override
+// public Path normalize() {
+// // always normalized
+// return this;
+// }
- @Override
- public WatchKey register(WatchService watcher, Kind<?>... events) throws IOException {
- // TODO Auto-generated method stub
- return null;
- }
+// @Override
+// public Path resolve(Path other) {
+// JcrPath otherPath = (JcrPath) other;
+// if (otherPath.isAbsolute())
+// return other;
+// String[] newPath;
+// if (path == null) {
+// newPath = new String[otherPath.path.length];
+// System.arraycopy(otherPath.path, 0, newPath, 0, otherPath.path.length);
+// } else {
+// newPath = new String[path.length + otherPath.path.length];
+// System.arraycopy(path, 0, newPath, 0, path.length);
+// System.arraycopy(otherPath.path, 0, newPath, path.length, otherPath.path.length);
+// }
+// if (!absolute)
+// return new JcrPath(fs, null, newPath, absolute);
+// else {
+// return new JcrPath(fs, toFsPath(newPath));
+// }
+// }
+//
+// @Override
+// public final Path resolve(String other) {
+// return resolve(getFileSystem().getPath(other));
+// }
+//
+// @Override
+// public final Path resolveSibling(Path other) {
+// if (other == null)
+// throw new NullPointerException();
+// Path parent = getParent();
+// return (parent == null) ? other : parent.resolve(other);
+// }
+//
+// @Override
+// public final Path resolveSibling(String other) {
+// return resolveSibling(getFileSystem().getPath(other));
+// }
+//
+// @Override
+// public final Iterator<Path> iterator() {
+// return new Iterator<Path>() {
+// private int i = 0;
+//
+// @Override
+// public boolean hasNext() {
+// return (i < getNameCount());
+// }
+//
+// @Override
+// public Path next() {
+// if (i < getNameCount()) {
+// Path result = getName(i);
+// i++;
+// return result;
+// } else {
+// throw new NoSuchElementException();
+// }
+// }
+//
+// @Override
+// public void remove() {
+// throw new UnsupportedOperationException();
+// }
+// };
+// }
+//
+// @Override
+// public Path relativize(Path other) {
+// if (equals(other))
+// return new JcrPath(fs, "");
+// if (other.startsWith(this)) {
+// String p1 = toString();
+// String p2 = other.toString();
+// String relative = p2.substring(p1.length(), p2.length());
+// if (relative.charAt(0) == '/')
+// relative = relative.substring(1);
+// return new JcrPath(fs, relative);
+// }
+// throw new IllegalArgumentException(other + " cannot be relativized against " + this);
+// }
- @Override
- public int compareTo(Path other) {
- return toString().compareTo(other.toString());
- }
+// @Override
+// public URI toUri() {
+// try {
+// return new URI(fs.provider().getScheme(), toString(), null);
+// } catch (URISyntaxException e) {
+// throw new JcrFsException("Cannot create URI for " + toString(), e);
+// }
+// }
+//
+// @Override
+// public Path toAbsolutePath() {
+// if (isAbsolute())
+// return this;
+// return new JcrPath(fs, fileStore, path, true);
+// }
+//
+// @Override
+// public Path toRealPath(LinkOption... options) throws IOException {
+// return this;
+// }
+//
+// @Override
+// public File toFile() {
+// throw new UnsupportedOperationException();
+// }
public Node getNode() throws RepositoryException {
if (!isAbsolute())// TODO default dir
throw new JcrFsException("Cannot get a JCR node from a relative path");
- assert fileStore != null;
- return fileStore.toNode(path);
+ assert getFileStore() != null;
+ return getFileStore().toNode(getSegments());
// String pathStr = toJcrPath();
// Session session = fs.getSession();
// // TODO synchronize on the session ?
// return null;
// return session.getNode(pathStr);
}
+//
+// @Override
+// public boolean equals(Object obj) {
+// if (!(obj instanceof JcrPath))
+// return false;
+// JcrPath other = (JcrPath) obj;
+//
+// if (path == null) {// root
+// if (other.path == null)// root
+// return true;
+// else
+// return false;
+// } else {
+// if (other.path == null)// root
+// return false;
+// }
+// // non root
+// if (path.length != other.path.length)
+// return false;
+// for (int i = 0; i < path.length; i++) {
+// if (!path[i].equals(other.path[i]))
+// return false;
+// }
+// return true;
+// }
- @Override
- public boolean equals(Object obj) {
- if (!(obj instanceof JcrPath))
- return false;
- JcrPath other = (JcrPath) obj;
-
- if (path == null) {// root
- if (other.path == null)// root
- return true;
- else
- return false;
- } else {
- if (other.path == null)// root
- return false;
- }
- // non root
- if (path.length != other.path.length)
- return false;
- for (int i = 0; i < path.length; i++) {
- if (!path[i].equals(other.path[i]))
- return false;
- }
- return true;
- }
-
- @Override
- public int hashCode() {
- return hashCode;
- }
+// @Override
+// public int hashCode() {
+// return hashCode;
+// }
- @Override
- protected Object clone() throws CloneNotSupportedException {
- return new JcrPath(fs, toString());
- }
+// @Override
+// protected Object clone() throws CloneNotSupportedException {
+// return new JcrPath(fs, toString());
+// }
- @Override
- protected void finalize() throws Throwable {
- Arrays.fill(path, null);
- }
+// @Override
+// protected void finalize() throws Throwable {
+// Arrays.fill(path, null);
+// }
+
+
}
import javax.jcr.Session;
import javax.jcr.Workspace;
+import org.argeo.api.gcr.fs.AbstractFsStore;
import org.argeo.jcr.JcrUtils;
/** A {@link FileStore} implementation based on JCR {@link Workspace}. */
-public class WorkspaceFileStore extends FileStore {
+public class WorkspaceFileStore extends AbstractFsStore {
private final String mountPath;
private final Workspace workspace;
private final String workspaceName;
--- /dev/null
+package org.argeo.cms.swt.gcr;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import org.argeo.api.gcr.Content;
+import org.argeo.cms.gcr.fs.FsContentSession;
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.swt.widgets.TableItem;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.TreeItem;
+
+public class GcrContentTreeView extends Composite {
+ private Tree tree;
+ private Table table;
+ private Content rootContent;
+
+ private Content selected;
+
+ public GcrContentTreeView(Composite parent, int style, Content content) {
+ super(parent, style);
+ this.rootContent = content;
+ this.selected = rootContent;
+ setLayout(new GridLayout(2, false));
+ initTree();
+ GridData treeGd = CmsSwtUtils.fillHeight();
+ treeGd.widthHint = 300;
+ tree.setLayoutData(treeGd);
+ initTable();
+
+ table.setLayoutData(CmsSwtUtils.fillAll());
+ }
+
+ protected void initTree() {
+ tree = new Tree(this, 0);
+ for (Content c : rootContent) {
+ TreeItem root = new TreeItem(tree, 0);
+ root.setText(c.getName());
+ root.setData(c);
+ new TreeItem(root, 0);
+ }
+ tree.addListener(SWT.Expand, event -> {
+ final TreeItem root = (TreeItem) event.item;
+ TreeItem[] items = root.getItems();
+ for (TreeItem item : items) {
+ if (item.getData() != null)
+ return;
+ item.dispose();
+ }
+ Content content = (Content) root.getData();
+ for (Content c : content) {
+ TreeItem item = new TreeItem(root, 0);
+ item.setText(c.getName());
+ item.setData(c);
+ boolean hasChildren = true;
+ if (hasChildren) {
+ new TreeItem(item, 0);
+ }
+ }
+ });
+ tree.addListener(SWT.Selection, event -> {
+ TreeItem item = (TreeItem) event.item;
+ selected = (Content) item.getData();
+ refreshTable();
+ });
+ }
+
+ protected void initTable() {
+ table = new Table(this, 0);
+ table.setLinesVisible(true);
+ table.setHeaderVisible(true);
+ TableColumn keyCol = new TableColumn(table, SWT.NONE);
+ keyCol.setText("Attribute");
+ keyCol.setWidth(200);
+ TableColumn valueCol = new TableColumn(table, SWT.NONE);
+ valueCol.setText("Value");
+ keyCol.setWidth(300);
+ refreshTable();
+ }
+
+ protected void refreshTable() {
+ for (TableItem item : table.getItems()) {
+ item.dispose();
+ }
+ for (String key : selected.keySet()) {
+ TableItem item = new TableItem(table, 0);
+ item.setText(0, key);
+ Object value = selected.get(key);
+ item.setText(1, value.toString());
+ }
+ table.getColumn(0).pack();
+ table.getColumn(1).pack();
+ }
+
+ public static void main(String[] args) {
+ Path basePath;
+ if (args.length > 0) {
+ basePath = Paths.get(args[0]);
+ } else {
+ basePath = Paths.get(System.getProperty("user.home"));
+ }
+
+ final Display display = new Display();
+ final Shell shell = new Shell(display);
+ shell.setText(basePath.toString());
+ shell.setLayout(new FillLayout());
+
+ FsContentSession contentSession = new FsContentSession(basePath);
+ GcrContentTreeView treeView = new GcrContentTreeView(shell, 0, contentSession.get());
+
+ shell.setSize(shell.computeSize(800, 600));
+ shell.open();
+ while (!shell.isDisposed()) {
+ if (!display.readAndDispatch())
+ display.sleep();
+ }
+ display.dispose();
+ }
+}
--- /dev/null
+package org.argeo.cms.swt.gcr;
+
+import org.argeo.api.cms.MvcProvider;
+import org.argeo.api.gcr.Content;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+
+@FunctionalInterface
+public interface SwtUiProvider extends MvcProvider<Composite, Content, Control> {
+
+}
import java.util.Iterator;
import java.util.Set;
-import org.argeo.api.gcr.AbstractContent;
import org.argeo.api.gcr.Content;
import org.argeo.api.gcr.ContentResourceException;
-import org.argeo.api.gcr.ContentSession;
+import org.argeo.api.gcr.ContentSystemProvider;
+import org.argeo.api.gcr.spi.AbstractContent;
public class FsContent extends AbstractContent implements Content {
private static final Set<String> BASIC_KEYS = new HashSet<>(
return (A) value;
}
- @Override
- public ContentSession getSession() {
- return contentSession;
- }
@Override
protected Iterable<String> keys() {
import java.nio.file.Paths;
import org.argeo.api.gcr.Content;
-import org.argeo.api.gcr.ContentSession;
-import org.argeo.api.gcr.Contents;
+import org.argeo.api.gcr.ContentSystemProvider;
+import org.argeo.api.gcr.ContentUtils;
-public class FsContentSession implements ContentSession {
+public class FsContentSession implements ContentSystemProvider {
private final Path rootPath;
public FsContentSession(Path rootPath) {
Path path = Paths.get("/home/mbaudier/tmp");
System.out.println(FileSystems.getDefault().supportedFileAttributeViews());
FsContentSession contentSession = new FsContentSession(path);
- Contents.traverse(contentSession.get(), (c, d) -> Contents.print(c, System.out, d, true));
+ ContentUtils.traverse(contentSession.get(), (c, d) -> ContentUtils.print(c, System.out, d, true));
}
}
import java.util.Iterator;
import java.util.Set;
-import org.argeo.api.gcr.AbstractContent;
import org.argeo.api.gcr.Content;
-import org.argeo.api.gcr.ContentSession;
+import org.argeo.api.gcr.ContentSystemProvider;
+import org.argeo.api.gcr.spi.AbstractContent;
import org.w3c.dom.Attr;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
return null;
}
- @Override
- public ContentSession getSession() {
- return contentSession;
- }
@Override
public boolean hasText() {
import javax.xml.parsers.DocumentBuilderFactory;
import org.argeo.api.gcr.Content;
-import org.argeo.api.gcr.ContentSession;
-import org.argeo.api.gcr.Contents;
+import org.argeo.api.gcr.ContentSystemProvider;
+import org.argeo.api.gcr.ContentUtils;
import org.w3c.dom.Document;
-public class DomContentSession implements ContentSession {
+public class DomContentSession implements ContentSystemProvider {
private Document document;
public DomContentSession(Document document) {
Document doc = dBuilder.parse(Files.newInputStream(testFile));
DomContentSession contentSession = new DomContentSession(doc);
- Contents.traverse(contentSession.get(), (c, d) -> Contents.print(c, System.out, d, true));
+ ContentUtils.traverse(contentSession.get(), (c, d) -> ContentUtils.print(c, System.out, d, true));
}
}