X-Git-Url: http://git.argeo.org/?a=blobdiff_plain;f=org.argeo.cms.jcr%2Fsrc%2Forg%2Fargeo%2Fcms%2Fjcr%2Facr%2FJcrContent.java;h=6a0cccb84fb8e9d0ae976a163e6f983c12e566bb;hb=41b3ea51a9fb6ed1ccb4e13897bcca3fbba00754;hp=30590640e05cc6a29b43f5b22eeeb90863a2b7a5;hpb=ceee6c4ebe8e30e19cf3a1cdae3267cbd8840d62;p=gpl%2Fargeo-jcr.git
diff --git a/org.argeo.cms.jcr/src/org/argeo/cms/jcr/acr/JcrContent.java b/org.argeo.cms.jcr/src/org/argeo/cms/jcr/acr/JcrContent.java
index 3059064..6a0cccb 100644
--- a/org.argeo.cms.jcr/src/org/argeo/cms/jcr/acr/JcrContent.java
+++ b/org.argeo.cms.jcr/src/org/argeo/cms/jcr/acr/JcrContent.java
@@ -3,63 +3,94 @@ package org.argeo.cms.jcr.acr;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
+import java.io.OutputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
+import java.time.Instant;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
+import java.util.Map;
+import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.TreeSet;
+import java.util.UUID;
import java.util.concurrent.ForkJoinPool;
+import javax.jcr.Binary;
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.Session;
import javax.jcr.Value;
+import javax.jcr.ValueFactory;
import javax.jcr.nodetype.NodeType;
+import javax.jcr.nodetype.NodeTypeManager;
import javax.xml.namespace.QName;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import org.argeo.api.acr.Content;
+import org.argeo.api.acr.CrAttributeType;
+import org.argeo.api.acr.DName;
import org.argeo.api.acr.NamespaceUtils;
-import org.argeo.api.acr.spi.ContentProvider;
import org.argeo.api.acr.spi.ProvidedSession;
import org.argeo.api.cms.CmsConstants;
import org.argeo.cms.acr.AbstractContent;
-import org.argeo.cms.acr.ContentUtils;
+import org.argeo.cms.acr.CmsContent;
+import org.argeo.cms.util.AsyncPipedOutputStream;
import org.argeo.jcr.Jcr;
import org.argeo.jcr.JcrException;
import org.argeo.jcr.JcrUtils;
+import org.argeo.jcr.JcrxApi;
/** A JCR {@link Node} accessed as {@link Content}. */
public class JcrContent extends AbstractContent {
-// private Node jcrNode;
-
private JcrContentProvider provider;
private String jcrWorkspace;
private String jcrPath;
+ private final boolean isMountBase;
+
+ /* OPTIMISATIONS */
+ /**
+ * While we want to support thread-safe access, it is very likely that only one
+ * thread and only one session will be used (typically from a single-threaded
+ * UI). We therefore cache was long as the same thread is calling.
+ */
+ private Thread lastRetrievingThread = null;
+ private Node cachedNode = null;
+ private boolean caching = true;
+
protected JcrContent(ProvidedSession session, JcrContentProvider provider, String jcrWorkspace, String jcrPath) {
super(session);
this.provider = provider;
this.jcrWorkspace = jcrWorkspace;
this.jcrPath = jcrPath;
+
+ this.isMountBase = "/".equals(jcrPath);
}
+ /*
+ * READ
+ */
+
@Override
public QName getName() {
String name = Jcr.getName(getJcrNode());
if (name.equals("")) {// root
String mountPath = provider.getMountPath();
- name = ContentUtils.getParentPath(mountPath)[1];
+ name = CmsContent.getParentPath(mountPath)[1];
// name = Jcr.getWorkspaceName(getJcrNode());
}
return NamespaceUtils.parsePrefixedName(provider, name);
@@ -68,10 +99,52 @@ public class JcrContent extends AbstractContent {
@SuppressWarnings("unchecked")
@Override
public Optional get(QName key, Class clss) {
- if (isDefaultAttrTypeRequested(clss)) {
- return Optional.of((A) get(getJcrNode(), key.toString()));
+ try {
+ Node node = getJcrNode();
+ if (DName.creationdate.equals(key))
+ key = JcrName.created.qName();
+ else if (DName.getlastmodified.equals(key))
+ key = JcrName.lastModified.qName();
+ else if (DName.getcontenttype.equals(key)) {
+ String contentType = null;
+ if (node.isNodeType(NodeType.NT_FILE)) {
+ Node content = node.getNode(Node.JCR_CONTENT);
+ if (content.isNodeType(NodeType.MIX_MIMETYPE)) {
+ contentType = content.getProperty(Property.JCR_MIMETYPE).getString();
+ if (content.hasProperty(Property.JCR_ENCODING))
+ contentType = contentType + ";encoding="
+ + content.getProperty(Property.JCR_ENCODING).getString();
+ }
+ }
+ if (contentType == null)
+ contentType = "application/octet-stream";
+ return CrAttributeType.cast(clss, contentType);
+ } else if (DName.checkedOut.equals(key)) {
+ if (!node.hasProperty(Property.JCR_IS_CHECKED_OUT))
+ return Optional.empty();
+ boolean isCheckedOut = node.getProperty(Property.JCR_IS_CHECKED_OUT).getBoolean();
+ if (!isCheckedOut)
+ return Optional.empty();
+ // FIXME return URI
+ return (Optional) Optional.of(new Object());
+ } else if (DName.checkedIn.equals(key)) {
+ if (!node.hasProperty(Property.JCR_IS_CHECKED_OUT))
+ return Optional.empty();
+ boolean isCheckedOut = node.getProperty(Property.JCR_IS_CHECKED_OUT).getBoolean();
+ if (isCheckedOut)
+ return Optional.empty();
+ // FIXME return URI
+ return (Optional) Optional.of(new Object());
+ }
+
+ Object value = get(node, key.toString());
+ if (value instanceof List> lst)
+ return Optional.of((A) lst);
+ // TODO check other collections?
+ return CrAttributeType.cast(clss, value);
+ } catch (RepositoryException e) {
+ throw new JcrException(e);
}
- return Optional.of((A) Jcr.get(getJcrNode(), key.toString()));
}
@Override
@@ -86,12 +159,25 @@ public class JcrContent extends AbstractContent {
@Override
protected Iterable keys() {
try {
+ Node node = getJcrNode();
Set keys = new HashSet<>();
- for (PropertyIterator propertyIterator = getJcrNode().getProperties(); propertyIterator.hasNext();) {
+ for (PropertyIterator propertyIterator = node.getProperties(); propertyIterator.hasNext();) {
Property property = propertyIterator.nextProperty();
+ QName name = NamespaceUtils.parsePrefixedName(provider, property.getName());
+
// TODO convert standard names
+ if (property.getName().equals(Property.JCR_CREATED))
+ name = DName.creationdate.qName();
+ else if (property.getName().equals(Property.JCR_LAST_MODIFIED))
+ name = DName.getlastmodified.qName();
+ else if (property.getName().equals(Property.JCR_MIMETYPE))
+ name = DName.getcontenttype.qName();
+ else if (property.getName().equals(Property.JCR_IS_CHECKED_OUT)) {
+ boolean isCheckedOut = node.getProperty(Property.JCR_IS_CHECKED_OUT).getBoolean();
+ name = isCheckedOut ? DName.checkedOut.qName() : DName.checkedIn.qName();
+ }
+
// TODO skip technical properties
- QName name = NamespaceUtils.parsePrefixedName(provider, property.getName());
keys.add(name);
}
return keys;
@@ -100,18 +186,11 @@ public class JcrContent extends AbstractContent {
}
}
- public Node getJcrNode() {
- try {
- // TODO caching?
- return provider.getJcrSession(getSession(), jcrWorkspace).getNode(jcrPath);
- } catch (RepositoryException e) {
- throw new JcrException("Cannot retrieve " + jcrPath + " from workspace " + jcrWorkspace, e);
- }
- }
-
/** Cast to a standard Java object. */
static Object get(Node node, String property) {
try {
+ if (!node.hasProperty(property))
+ return null;
Property p = node.getProperty(property);
if (p.isMultiple()) {
Value[] values = p.getValues();
@@ -125,57 +204,25 @@ public class JcrContent extends AbstractContent {
return convertSingleValue(value);
}
} catch (RepositoryException e) {
- throw new JcrException("Cannot cast value from " + property + " of node " + node, e);
- }
- }
-
- static Object convertSingleValue(Value value) throws RepositoryException {
- 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();
+ throw new JcrException("Cannot cast value from " + property + " of " + node, e);
}
}
- class JcrContentIterator implements Iterator {
- private final NodeIterator nodeIterator;
- // we keep track in order to be able to delete it
- private JcrContent current = null;
-
- protected JcrContentIterator(NodeIterator nodeIterator) {
- this.nodeIterator = nodeIterator;
- }
-
- @Override
- public boolean hasNext() {
- return nodeIterator.hasNext();
- }
-
- @Override
- public Content next() {
- current = new JcrContent(getSession(), provider, jcrWorkspace, Jcr.getPath(nodeIterator.nextNode()));
- return current;
- }
-
- @Override
- public void remove() {
- if (current != null) {
- Jcr.remove(current.getJcrNode());
+ @Override
+ public boolean isMultiple(QName key) {
+ Node node = getJcrNode();
+ String p = NamespaceUtils.toFullyQualified(key);
+ try {
+ if (node.hasProperty(p)) {
+ Property property = node.getProperty(p);
+ return property.isMultiple();
+ } else {
+ return false;
}
+ } catch (RepositoryException e) {
+ throw new JcrException(
+ "Cannot check multiplicity of property " + p + " of " + jcrPath + " in " + jcrWorkspace, e);
}
-
}
@Override
@@ -183,7 +230,7 @@ public class JcrContent extends AbstractContent {
try {
// Note: it is important to to use the default way (recursing through parents),
// since the session may not have access to parent nodes
- return ContentUtils.ROOT_SLASH + jcrWorkspace + getJcrNode().getPath();
+ return Content.ROOT_PATH + jcrWorkspace + getJcrNode().getPath();
} catch (RepositoryException e) {
throw new JcrException("Cannot get depth of " + getJcrNode(), e);
}
@@ -200,38 +247,114 @@ public class JcrContent extends AbstractContent {
@Override
public Content getParent() {
- if (Jcr.isRoot(getJcrNode())) // root
- return null;
+ if (isMountBase) {
+ String mountPath = provider.getMountPath();
+ if (mountPath == null || mountPath.equals("/"))
+ return null;
+ String[] parent = CmsContent.getParentPath(mountPath);
+ return getSession().get(parent[0]);
+ }
+// if (Jcr.isRoot(getJcrNode())) // root
+// return null;
return new JcrContent(getSession(), provider, jcrWorkspace, Jcr.getParentPath(getJcrNode()));
}
+ @Override
+ public int getSiblingIndex() {
+ return Jcr.getIndex(getJcrNode());
+ }
+
+ @Override
+ public String getText() {
+ return JcrxApi.getXmlValue(getJcrNode());
+ }
+
+ /*
+ * MAP OPTIMISATIONS
+ */
+ @Override
+ public boolean containsKey(Object key) {
+ return Jcr.hasProperty(getJcrNode(), key.toString());
+ }
+
+ /*
+ * WRITE
+ */
+
+ protected Node openForEdit() {
+ Node node = getProvider().openForEdit(getSession(), jcrWorkspace, jcrPath);
+ getSession().notifyModification(this);
+ return node;
+ }
+
@Override
public Content add(QName name, QName... classes) {
- if (classes.length > 0) {
- QName primaryType = classes[0];
- Node child = Jcr.addNode(getJcrNode(), name.toString(), primaryType.toString());
- for (int i = 1; i < classes.length; i++) {
- try {
+ try {
+ Node node = openForEdit();
+ Node child;
+ if (classes.length > 0) {
+ classes: for (int i = 0; i < classes.length; i++) {
+ if (classes[i].equals(DName.collection.qName())) {
+ List lst = new ArrayList<>(Arrays.asList(classes));
+ lst.add(0, NtType.folder.qName());
+ lst.remove(DName.collection.qName());
+ classes = lst.toArray(new QName[lst.size()]);
+ break classes;
+ }
+ }
+ QName primaryType = classes[0];
+ child = Jcr.addNode(node, name.toString(), primaryType.toString());
+
+ for (int i = 1; i < classes.length; i++)
child.addMixin(classes[i].toString());
- } catch (RepositoryException e) {
- throw new JcrException("Cannot add child to " + getJcrNode(), e);
+
+ if (NtType.file.qName().equals(primaryType)) {
+ // TODO optimise when we have a proper save mechanism
+ child.addNode(Node.JCR_CONTENT, NodeType.NT_UNSTRUCTURED);
}
+ } else {
+ child = Jcr.addNode(node, name.toString(), NodeType.NT_UNSTRUCTURED);
}
+ saveEditedNode(node);
+ return new JcrContent(getSession(), provider, jcrWorkspace, child.getPath());
+ } catch (RepositoryException e) {
+ throw new JcrException("Cannot add child to " + jcrPath + " in " + jcrWorkspace, e);
+ }
+ }
- } else {
- Jcr.addNode(getJcrNode(), name.toString(), NodeType.NT_UNSTRUCTURED);
+ @Override
+ public Content add(QName name, Map attrs, QName... classes) {
+ if (attrs.containsKey(DName.getcontenttype.qName())) {
+ List lst = new ArrayList<>(Arrays.asList(classes));
+ lst.add(0, NtType.file.qName());
+ classes = lst.toArray(new QName[lst.size()]);
}
- return null;
+
+ Content child = add(name, classes);
+ child.putAll(attrs);
+ return child;
}
@Override
public void remove() {
- Jcr.remove(getJcrNode());
+ Node node = openForEdit();
+ Jcr.remove(node);
+ saveEditedNode(node);
+ }
+
+ private void saveEditedNode(Node node) {
+ try {
+ node.getSession().save();
+ getJcrSession().refresh(true);
+ } catch (RepositoryException e) {
+ throw new JcrException("Cannot persist " + jcrPath + " in " + jcrWorkspace, e);
+ }
}
@Override
protected void removeAttr(QName key) {
- Property property = Jcr.getProperty(getJcrNode(), key.toString());
+ Node node = openForEdit();
+ Property property = Jcr.getProperty(node, key.toString());
if (property != null) {
try {
property.remove();
@@ -239,23 +362,117 @@ public class JcrContent extends AbstractContent {
throw new JcrException("Cannot remove property " + key + " from " + getJcrNode(), e);
}
}
+ saveEditedNode(node);
+ }
+ @Override
+ public Object put(QName key, Object value) {
+ Objects.requireNonNull(value, "Value cannot be null");
+ Node node = openForEdit();
+ try {
+ if (DName.checkedIn.equals(key) || DName.checkedOut.equals(key))
+ throw new IllegalArgumentException(
+ key + " cannot be set, use the openForEdit/freeze methods of the related content provider.");
+
+ Object old = null;
+ String property;
+ if (DName.creationdate.equals(key))
+ property = Property.JCR_CREATED;
+ else if (DName.getlastmodified.equals(key))
+ property = Property.JCR_LAST_MODIFIED;
+ else if (DName.getcontenttype.equals(key)) {
+ if (!node.isNodeType(NodeType.NT_FILE))
+ throw new IllegalStateException(DName.getcontenttype + " can only be set on a file");
+ Node content = node.getNode(Node.JCR_CONTENT);
+ old = Jcr.get(content, Property.JCR_MIMETYPE);
+ if (old != null && Jcr.hasProperty(content, Property.JCR_ENCODING))
+ old = old + ";encoding=" + Jcr.get(content, Property.JCR_ENCODING);
+ String[] str = value.toString().split(";");
+ String mimeType = str[0].trim();
+ String encoding = null;
+ if (str.length > 1) {
+ value = str[0].trim();
+ String[] eq = str[1].split("=");
+ assert eq.length == 2;
+ if ("encoding".equals(eq[0].trim()))
+ encoding = eq[1];
+ }
+ content.setProperty(Property.JCR_MIMETYPE, mimeType);
+ if (encoding != null)
+ content.setProperty(Property.JCR_ENCODING, encoding);
+ property = null;
+ } else
+ property = NamespaceUtils.toFullyQualified(key);
+
+ if (property != null) {
+ if (node.hasProperty(property)) {
+ old = convertSingleValue(node.getProperty(property).getValue());
+ }
+ Value newValue = convertSingleObject(node.getSession().getValueFactory(), value);
+ node.setProperty(property, newValue);
+ }
+ // FIXME proper edition
+ saveEditedNode(node);
+ return old;
+ } catch (RepositoryException e) {
+ throw new JcrException("Cannot set property " + key + " on " + jcrPath + " in " + jcrWorkspace, e);
+ }
}
- boolean exists() {
+ @Override
+ public void addContentClasses(QName... contentClass) throws IllegalArgumentException, JcrException {
try {
- return provider.getJcrSession(getSession(), jcrWorkspace).itemExists(jcrPath);
+ Node node = openForEdit();
+ NodeTypeManager ntm = node.getSession().getWorkspace().getNodeTypeManager();
+ List nodeTypes = new ArrayList<>();
+ for (QName clss : contentClass) {
+ NodeType nodeType = ntm.getNodeType(NamespaceUtils.toFullyQualified(clss));
+ if (!nodeType.isMixin())
+ throw new IllegalArgumentException(clss + " is not a mixin");
+ nodeTypes.add(nodeType);
+ }
+ for (NodeType nodeType : nodeTypes) {
+ node.addMixin(nodeType.getName());
+ }
+ // FIXME proper edition
+ saveEditedNode(node);
+ } catch (RepositoryException e) {
+ throw new JcrException(
+ "Cannot add content classes " + contentClass + " to " + jcrPath + " in " + jcrWorkspace, e);
+ }
+ }
+
+ /*
+ * ACCESS
+ */
+ protected boolean exists() {
+ try {
+ return getJcrSession().itemExists(jcrPath);
} catch (RepositoryException e) {
throw new JcrException("Cannot check whether " + jcrPath + " exists", e);
}
}
+ @Override
+ public boolean isParentAccessible() {
+ String jcrParentPath = CmsContent.getParentPath(jcrPath)[0];
+ if ("".equals(jcrParentPath)) // JCR root node
+ jcrParentPath = "/";
+ try {
+ return getJcrSession().hasPermission(jcrParentPath, Session.ACTION_READ);
+ } catch (RepositoryException e) {
+ throw new JcrException("Cannot check whether parent " + jcrParentPath + " is accessible", e);
+ }
+ }
+
/*
* ADAPTERS
*/
@SuppressWarnings("unchecked")
public A adapt(Class clss) {
- if (Source.class.isAssignableFrom(clss)) {
+ if (Node.class.isAssignableFrom(clss)) {
+ return (A) getJcrNode();
+ } else if (Source.class.isAssignableFrom(clss)) {
// try {
PipedOutputStream out = new PipedOutputStream();
PipedInputStream in;
@@ -268,7 +485,7 @@ public class JcrContent extends AbstractContent {
ForkJoinPool.commonPool().execute(() -> {
// try (PipedOutputStream out = new PipedOutputStream(in)) {
try {
- provider.getJcrSession(getSession(), jcrWorkspace).exportDocumentView(jcrPath, out, true, false);
+ getJcrSession().exportDocumentView(jcrPath, out, true, false);
out.flush();
out.close();
} catch (IOException | RepositoryException e) {
@@ -280,29 +497,50 @@ public class JcrContent extends AbstractContent {
// } catch (IOException e) {
// throw new RuntimeException("Cannot adapt " + JcrContent.this + " to " + clss, e);
// }
- } else
-
+ } else {
return super.adapt(clss);
+ }
}
@SuppressWarnings("unchecked")
@Override
public C open(Class clss) throws IOException, IllegalArgumentException {
- if (InputStream.class.isAssignableFrom(clss)) {
- Node node = getJcrNode();
- if (Jcr.isNodeType(node, NodeType.NT_FILE)) {
- try {
+ try {
+ if (InputStream.class.isAssignableFrom(clss)) {
+ Node node = getJcrNode();
+// System.out.println(node.getSession());
+ if (Jcr.isNodeType(node, NodeType.NT_FILE)) {
return (C) JcrUtils.getFileAsStream(node);
- } catch (RepositoryException e) {
- throw new JcrException("Cannot open " + jcrPath + " in workspace " + jcrWorkspace, e);
+ }
+ } else if (OutputStream.class.isAssignableFrom(clss)) {
+ Node node = openForEdit();
+// System.out.println(node.getSession());
+ if (Jcr.isNodeType(node, NodeType.NT_FILE)) {
+ Node content = node.getNode(Node.JCR_CONTENT);
+ AsyncPipedOutputStream out = new AsyncPipedOutputStream();
+
+ ValueFactory valueFactory = getJcrSession().getValueFactory();
+ out.asyncRead((in) -> {
+ try {
+ Binary binary = valueFactory.createBinary(in);
+ content.setProperty(Property.JCR_DATA, binary);
+ saveEditedNode(node);
+ } catch (RepositoryException e) {
+ throw new JcrException(
+ "Cannot create binary in " + jcrPath + " in workspace " + jcrWorkspace, e);
+ }
+ });
+ return (C) out;
}
}
+ } catch (RepositoryException e) {
+ throw new JcrException("Cannot open " + jcrPath + " in workspace " + jcrWorkspace, e);
}
return super.open(clss);
}
@Override
- public ContentProvider getProvider() {
+ public JcrContentProvider getProvider() {
return provider;
}
@@ -318,22 +556,101 @@ public class JcrContent extends AbstractContent {
/*
* TYPING
*/
+
+ static Object convertSingleValue(Value value) throws JcrException, IllegalArgumentException {
+ try {
+ 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 convert " + value + " to an object.", e);
+ }
+ }
+
+ static Value convertSingleObject(ValueFactory factory, Object value) {
+ if (value instanceof String string) {
+ return factory.createValue(string);
+ } else if (value instanceof Double dbl) {
+ return factory.createValue(dbl);
+ } else if (value instanceof Float flt) {
+ return factory.createValue(flt);
+ } else if (value instanceof Long lng) {
+ return factory.createValue(lng);
+ } else if (value instanceof Integer intg) {
+ return factory.createValue(intg);
+ } else if (value instanceof Boolean bool) {
+ return factory.createValue(bool);
+ } else if (value instanceof Instant instant) {
+ GregorianCalendar calendar = new GregorianCalendar();
+ calendar.setTime(Date.from(instant));
+ return factory.createValue(calendar);
+ } else {
+ // TODO or use String by default?
+ throw new IllegalArgumentException("Unsupported value " + value.getClass());
+ }
+ }
+
+ @Override
+ public Class> getType(QName key) {
+ Node node = getJcrNode();
+ String p = NamespaceUtils.toFullyQualified(key);
+ try {
+ if (node.hasProperty(p)) {
+ Property property = node.getProperty(p);
+ return switch (property.getType()) {
+ case PropertyType.STRING:
+ case PropertyType.NAME:
+ case PropertyType.PATH:
+ case PropertyType.DECIMAL:
+ yield String.class;
+ case PropertyType.LONG:
+ yield Long.class;
+ case PropertyType.DOUBLE:
+ yield Double.class;
+ case PropertyType.BOOLEAN:
+ yield Boolean.class;
+ case PropertyType.DATE:
+ yield Instant.class;
+ case PropertyType.WEAKREFERENCE:
+ case PropertyType.REFERENCE:
+ yield UUID.class;
+ default:
+ yield Object.class;
+ };
+ } else {
+ // TODO does it make sense?
+ return Object.class;
+ }
+ } catch (RepositoryException e) {
+ throw new JcrException("Cannot get type of property " + p + " of " + jcrPath + " in " + jcrWorkspace, e);
+ }
+ }
+
@Override
public List getContentClasses() {
try {
-// Node node = getJcrNode();
-// List res = new ArrayList<>();
-// res.add(nodeTypeToQName(node.getPrimaryNodeType()));
-// for (NodeType mixin : node.getMixinNodeTypes()) {
-// res.add(nodeTypeToQName(mixin));
-// }
-// return res;
Node context = getJcrNode();
List res = new ArrayList<>();
// primary node type
NodeType primaryType = context.getPrimaryNodeType();
res.add(nodeTypeToQName(primaryType));
+ if (primaryType.getName().equals(NodeType.NT_FOLDER))
+ res.add(DName.collection.qName());
Set secondaryTypes = new TreeSet<>(NamespaceUtils.QNAME_COMPARATOR);
for (NodeType mixinType : context.getMixinNodeTypes()) {
@@ -348,15 +665,6 @@ public class JcrContent extends AbstractContent {
secondaryTypes.add(nodeTypeToQName(superType));
}
}
-// // entity type
-// if (context.isNodeType(EntityType.entity.get())) {
-// if (context.hasProperty(EntityNames.ENTITY_TYPE)) {
-// String entityTypeName = context.getProperty(EntityNames.ENTITY_TYPE).getString();
-// if (byType.containsKey(entityTypeName)) {
-// types.add(entityTypeName);
-// }
-// }
-// }
res.addAll(secondaryTypes);
return res;
} catch (RepositoryException e) {
@@ -366,12 +674,40 @@ public class JcrContent extends AbstractContent {
private QName nodeTypeToQName(NodeType nodeType) {
String name = nodeType.getName();
- return QName.valueOf(name);
+ return NamespaceUtils.parsePrefixedName(provider, name);
+ // return QName.valueOf(name);
}
- @Override
- public int getSiblingIndex() {
- return Jcr.getIndex(getJcrNode());
+ /*
+ * COMMON UTILITIES
+ */
+ protected Session getJcrSession() {
+ Session s = provider.getJcrSession(getSession(), jcrWorkspace);
+// if (getSession().isEditing())
+// try {
+// s.refresh(false);
+// } catch (RepositoryException e) {
+// throw new JcrException("Cannot refresh session", e);
+// }
+ return s;
+ }
+
+ protected Node getJcrNode() {
+ try {
+ if (caching) {
+ synchronized (this) {
+ if (lastRetrievingThread != Thread.currentThread()) {
+ cachedNode = getJcrSession().getNode(jcrPath);
+ lastRetrievingThread = Thread.currentThread();
+ }
+ return cachedNode;
+ }
+ } else {
+ return getJcrSession().getNode(jcrPath);
+ }
+ } catch (RepositoryException e) {
+ throw new JcrException("Cannot retrieve " + jcrPath + " from workspace " + jcrWorkspace, e);
+ }
}
/*
@@ -386,10 +722,43 @@ public class JcrContent extends AbstractContent {
if (contentSession == null)
throw new IllegalArgumentException(
"Cannot adapt " + node + " to content, because it was not loaded from a content session");
- return contentSession.get(ContentUtils.SLASH + CmsConstants.SYS_WORKSPACE + node.getPath());
+ return contentSession.get(Content.ROOT_PATH + CmsConstants.SYS_WORKSPACE + node.getPath());
} catch (RepositoryException e) {
throw new JcrException("Cannot adapt " + node + " to a content", e);
}
}
+ /*
+ * CONTENT ITERATOR
+ */
+
+ class JcrContentIterator implements Iterator {
+ private final NodeIterator nodeIterator;
+ // we keep track in order to be able to delete it
+ private JcrContent current = null;
+
+ protected JcrContentIterator(NodeIterator nodeIterator) {
+ this.nodeIterator = nodeIterator;
+ }
+
+ @Override
+ public boolean hasNext() {
+ return nodeIterator.hasNext();
+ }
+
+ @Override
+ public Content next() {
+ current = new JcrContent(getSession(), provider, jcrWorkspace, Jcr.getPath(nodeIterator.nextNode()));
+ return current;
+ }
+
+ @Override
+ public void remove() {
+ if (current != null) {
+ Jcr.remove(current.getJcrNode());
+ }
+ }
+
+ }
+
}