SLING-6723 : Make dependency to javax.jcr, jcr.contentloader and jcr.api optional
git-svn-id: https://svn.apache.org/repos/asf/sling/trunk@1792881 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/src/main/java/org/apache/sling/servlets/post/impl/helper/JCRSupport.java b/src/main/java/org/apache/sling/servlets/post/impl/helper/JCRSupport.java
index bba35da..45330e1 100644
--- a/src/main/java/org/apache/sling/servlets/post/impl/helper/JCRSupport.java
+++ b/src/main/java/org/apache/sling/servlets/post/impl/helper/JCRSupport.java
@@ -188,6 +188,13 @@
return null;
}
+ public Object getItem(final Resource rsrc) {
+ if ( supportImpl != null ) {
+ return ((JCRSupportImpl)supportImpl).getItem(rsrc);
+ }
+ return null;
+ }
+
public void setPrimaryNodeType(final Object node, final String type)
throws PersistenceException {
if ( node != null && supportImpl != null ) {
@@ -196,4 +203,16 @@
throw new PersistenceException("Node type should be set but JCR support is not available");
}
}
+
+ public String copy(Object src, Object dstParent, String name)
+ throws PersistenceException {
+ // the caller already got an item and a node, so supportImpl is available
+ return ((JCRSupportImpl)supportImpl).copy(src, dstParent, name);
+ }
+
+ public void move(Object src, Object dstParent, String name)
+ throws PersistenceException {
+ // the caller already got an item and a node, so supportImpl is available
+ ((JCRSupportImpl)supportImpl).move(src, dstParent, name);
+ }
}
diff --git a/src/main/java/org/apache/sling/servlets/post/impl/helper/JCRSupportImpl.java b/src/main/java/org/apache/sling/servlets/post/impl/helper/JCRSupportImpl.java
index 9aa9cd0..ed641b0 100644
--- a/src/main/java/org/apache/sling/servlets/post/impl/helper/JCRSupportImpl.java
+++ b/src/main/java/org/apache/sling/servlets/post/impl/helper/JCRSupportImpl.java
@@ -20,10 +20,12 @@
import java.util.List;
+import javax.jcr.Item;
import javax.jcr.ItemNotFoundException;
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;
@@ -395,6 +397,10 @@
return rsrc.adaptTo(Node.class);
}
+ public Object getItem(final Resource rsrc) {
+ return rsrc.adaptTo(Item.class);
+ }
+
public void setPrimaryNodeType(final Object node, final String type)
throws PersistenceException {
try {
@@ -403,4 +409,148 @@
throw new PersistenceException(re.getMessage(), re);
}
}
+
+ public void move(Object src, Object dstParent, String name)
+ throws PersistenceException {
+ try {
+ final Session session = ((Item)src).getSession();
+ session.move(((Item)src).getPath(), ((Node)dstParent).getPath() + '/' + name);
+ } catch ( final RepositoryException re) {
+ throw new PersistenceException(re.getMessage(), re);
+ }
+ }
+
+ /**
+ * Copy the <code>src</code> item into the <code>dstParent</code> node.
+ * The name of the newly created item is set to <code>name</code>.
+ *
+ * @param src The item to copy to the new location
+ * @param dstParent The node into which the <code>src</code> node is to be
+ * copied
+ * @param name The name of the newly created item. If this is
+ * <code>null</code> the new item gets the same name as the
+ * <code>src</code> item.
+ * @throws PersistenceException May be thrown in case of any problem copying
+ * the content.
+ * @see #copy(Node, Node, String)
+ * @see #copy(Property, Node, String)
+ */
+ public String copy(Object src, Object dstParent, String name)
+ throws PersistenceException {
+ try {
+ final Item result;
+ if (((Item)src).isNode()) {
+ result = copy((Node) src, (Node)dstParent, name);
+ } else {
+ result = copy((Property) src, (Node)dstParent, name);
+ }
+ return result.getPath();
+ } catch ( final RepositoryException re) {
+ throw new PersistenceException(re.getMessage(), re);
+ }
+ }
+
+ /**
+ * Copy the <code>src</code> node into the <code>dstParent</code> node.
+ * The name of the newly created node is set to <code>name</code>.
+ * <p>
+ * This method does a recursive (deep) copy of the subtree rooted at the
+ * source node to the destination. Any protected child nodes and and
+ * properties are not copied.
+ *
+ * @param src The node to copy to the new location
+ * @param dstParent The node into which the <code>src</code> node is to be
+ * copied
+ * @param name The name of the newly created node. If this is
+ * <code>null</code> the new node gets the same name as the
+ * <code>src</code> node.
+ * @throws RepositoryException May be thrown in case of any problem copying
+ * the content.
+ */
+ private Item copy(Node src, Node dstParent, String name)
+ throws RepositoryException {
+
+ if(isAncestorOrSameNode(src, dstParent)) {
+ throw new RepositoryException(
+ "Cannot copy ancestor " + src.getPath() + " to descendant " + dstParent.getPath());
+ }
+
+ // ensure destination name
+ if (name == null) {
+ name = src.getName();
+ }
+
+ // ensure new node creation
+ if (dstParent.hasNode(name)) {
+ dstParent.getNode(name).remove();
+ }
+
+ // create new node
+ Node dst = dstParent.addNode(name, src.getPrimaryNodeType().getName());
+ for (NodeType mix : src.getMixinNodeTypes()) {
+ dst.addMixin(mix.getName());
+ }
+
+ // copy the properties
+ for (PropertyIterator iter = src.getProperties(); iter.hasNext();) {
+ copy(iter.nextProperty(), dst, null);
+ }
+
+ // copy the child nodes
+ for (NodeIterator iter = src.getNodes(); iter.hasNext();) {
+ Node n = iter.nextNode();
+ if (!n.getDefinition().isProtected()) {
+ copy(n, dst, null);
+ }
+ }
+ return dst;
+ }
+
+ /** @return true if src is an ancestor node of dest, or if
+ * both are the same node */
+ public static boolean isAncestorOrSameNode(Node src, Node dest) throws RepositoryException {
+ if(src.getPath().equals("/")) {
+ return true;
+ } else if(src.getPath().equals(dest.getPath())) {
+ return true;
+ } else if(dest.getPath().startsWith(src.getPath() + "/")) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Copy the <code>src</code> property into the <code>dstParent</code>
+ * node. The name of the newly created property is set to <code>name</code>.
+ * <p>
+ * If the source property is protected, this method does nothing.
+ *
+ * @param src The property to copy to the new location
+ * @param dstParent The node into which the <code>src</code> property is
+ * to be copied
+ * @param name The name of the newly created property. If this is
+ * <code>null</code> the new property gets the same name as the
+ * <code>src</code> property.
+ * @throws RepositoryException May be thrown in case of any problem copying
+ * the content.
+ */
+ private Item copy(Property src, Node dstParent, String name)
+ throws RepositoryException {
+ if (!src.getDefinition().isProtected()) {
+ if (name == null) {
+ name = src.getName();
+ }
+
+ // ensure new property creation
+ if (dstParent.hasProperty(name)) {
+ dstParent.getProperty(name).remove();
+ }
+
+ if (src.getDefinition().isMultiple()) {
+ return dstParent.setProperty(name, src.getValues());
+ }
+ return dstParent.setProperty(name, src.getValue());
+ }
+ return null;
+ }
}
diff --git a/src/main/java/org/apache/sling/servlets/post/impl/operations/CopyOperation.java b/src/main/java/org/apache/sling/servlets/post/impl/operations/CopyOperation.java
index fd918f5..340bf57 100644
--- a/src/main/java/org/apache/sling/servlets/post/impl/operations/CopyOperation.java
+++ b/src/main/java/org/apache/sling/servlets/post/impl/operations/CopyOperation.java
@@ -18,16 +18,9 @@
import java.util.List;
-import javax.jcr.Item;
-import javax.jcr.Node;
-import javax.jcr.NodeIterator;
-import javax.jcr.Property;
-import javax.jcr.PropertyIterator;
-import javax.jcr.RepositoryException;
-import javax.jcr.nodetype.NodeType;
-
import org.apache.sling.api.resource.PersistenceException;
import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.servlets.post.Modification;
import org.apache.sling.servlets.post.VersioningConfiguration;
@@ -50,149 +43,33 @@
final String destName,
final VersioningConfiguration versioningConfiguration)
throws PersistenceException {
- try {
- // ensure we have an item underlying the request's resource
- Item item = source.adaptTo(Item.class);
- if (item == null) {
- return null;
- }
-
- Item destItem = copy(item, (Node) item.getSession().getItem(destParent), destName);
-
- String dest = destParent + "/" + destName;
+ final Resource parentRsrc = source.getResourceResolver().getResource(destParent);
+ // check if the item is backed by JCR
+ final Object item = this.jcrSsupport.getItem(source);
+ final Object parentItem = this.jcrSsupport.getNode(parentRsrc);
+ if ( item == null || parentItem == null ) {
+ // no JCR, copy via resources
+ final Resource result = copy(source, parentRsrc);
+ changes.add(Modification.onCopied(source.getPath(), result.getPath()));
+ return result;
+ } else {
+ final String dest = this.jcrSsupport.copy(item, parentItem, destName);
changes.add(Modification.onCopied(source.getPath(), dest));
log.debug("copy {} to {}", source, dest);
- return source.getResourceResolver().getResource(destItem.getPath());
- } catch ( final RepositoryException re) {
- throw new PersistenceException(re.getMessage(), re, source.getPath(), null);
+ return source.getResourceResolver().getResource(dest);
}
}
/**
- * Copy the <code>src</code> item into the <code>dstParent</code> node.
- * The name of the newly created item is set to <code>name</code>.
- *
- * @param src The item to copy to the new location
- * @param dstParent The node into which the <code>src</code> node is to be
- * copied
- * @param name The name of the newly created item. If this is
- * <code>null</code> the new item gets the same name as the
- * <code>src</code> item.
- * @throws RepositoryException May be thrown in case of any problem copying
- * the content.
- * @see #copy(Node, Node, String)
- * @see #copy(Property, Node, String)
+ * Copy the source as a child resource to the parent
*/
- static Item copy(Item src, Node dstParent, String name)
- throws RepositoryException {
- if (src.isNode()) {
- return copy((Node) src, dstParent, name);
+ private Resource copy(final Resource source, final Resource dest)
+ throws PersistenceException {
+ final ValueMap vm = source.getValueMap();
+ final Resource result = source.getResourceResolver().create(dest, source.getName(), vm);
+ for(final Resource c : source.getChildren()) {
+ copy(c, result);
}
- return copy((Property) src, dstParent, name);
+ return result;
}
-
- /**
- * Copy the <code>src</code> node into the <code>dstParent</code> node.
- * The name of the newly created node is set to <code>name</code>.
- * <p>
- * This method does a recursive (deep) copy of the subtree rooted at the
- * source node to the destination. Any protected child nodes and and
- * properties are not copied.
- *
- * @param src The node to copy to the new location
- * @param dstParent The node into which the <code>src</code> node is to be
- * copied
- * @param name The name of the newly created node. If this is
- * <code>null</code> the new node gets the same name as the
- * <code>src</code> node.
- * @throws RepositoryException May be thrown in case of any problem copying
- * the content.
- */
- static Item copy(Node src, Node dstParent, String name)
- throws RepositoryException {
-
- if(isAncestorOrSameNode(src, dstParent)) {
- throw new RepositoryException(
- "Cannot copy ancestor " + src.getPath() + " to descendant " + dstParent.getPath());
- }
-
- // ensure destination name
- if (name == null) {
- name = src.getName();
- }
-
- // ensure new node creation
- if (dstParent.hasNode(name)) {
- dstParent.getNode(name).remove();
- }
-
- // create new node
- Node dst = dstParent.addNode(name, src.getPrimaryNodeType().getName());
- for (NodeType mix : src.getMixinNodeTypes()) {
- dst.addMixin(mix.getName());
- }
-
- // copy the properties
- for (PropertyIterator iter = src.getProperties(); iter.hasNext();) {
- copy(iter.nextProperty(), dst, null);
- }
-
- // copy the child nodes
- for (NodeIterator iter = src.getNodes(); iter.hasNext();) {
- Node n = iter.nextNode();
- if (!n.getDefinition().isProtected()) {
- copy(n, dst, null);
- }
- }
- return dst;
- }
-
- /** @return true if src is an ancestor node of dest, or if
- * both are the same node */
- static boolean isAncestorOrSameNode(Node src, Node dest) throws RepositoryException {
- if(src.getPath().equals("/")) {
- return true;
- } else if(src.getPath().equals(dest.getPath())) {
- return true;
- } else if(dest.getPath().startsWith(src.getPath() + "/")) {
- return true;
- }
- return false;
- }
-
- /**
- * Copy the <code>src</code> property into the <code>dstParent</code>
- * node. The name of the newly created property is set to <code>name</code>.
- * <p>
- * If the source property is protected, this method does nothing.
- *
- * @param src The property to copy to the new location
- * @param dstParent The node into which the <code>src</code> property is
- * to be copied
- * @param name The name of the newly created property. If this is
- * <code>null</code> the new property gets the same name as the
- * <code>src</code> property.
- * @throws RepositoryException May be thrown in case of any problem copying
- * the content.
- */
- static Item copy(Property src, Node dstParent, String name)
- throws RepositoryException {
- if (!src.getDefinition().isProtected()) {
- if (name == null) {
- name = src.getName();
- }
-
- // ensure new property creation
- if (dstParent.hasProperty(name)) {
- dstParent.getProperty(name).remove();
- }
-
- if (src.getDefinition().isMultiple()) {
- return dstParent.setProperty(name, src.getValues());
- }
- return dstParent.setProperty(name, src.getValue());
- }
- return null;
- }
-
}
diff --git a/src/main/java/org/apache/sling/servlets/post/impl/operations/ModifyOperation.java b/src/main/java/org/apache/sling/servlets/post/impl/operations/ModifyOperation.java
index 1ded8c7..158f8ef 100644
--- a/src/main/java/org/apache/sling/servlets/post/impl/operations/ModifyOperation.java
+++ b/src/main/java/org/apache/sling/servlets/post/impl/operations/ModifyOperation.java
@@ -21,14 +21,9 @@
import java.util.List;
import java.util.Map;
-import javax.jcr.Item;
-import javax.jcr.Node;
-import javax.jcr.Property;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.jcr.nodetype.NodeType;
import javax.servlet.ServletContext;
+import org.apache.jackrabbit.JcrConstants;
import org.apache.sling.api.SlingException;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.resource.ModifiableValueMap;
@@ -78,33 +73,28 @@
final PostResponse response,
final List<Modification> changes)
throws PersistenceException {
+ final Map<String, RequestProperty> reqProperties = collectContent(request, response);
- try {
- final Map<String, RequestProperty> reqProperties = collectContent(request, response);
+ final VersioningConfiguration versioningConfiguration = getVersioningConfiguration(request);
- final VersioningConfiguration versioningConfiguration = getVersioningConfiguration(request);
+ // do not change order unless you have a very good reason.
- // do not change order unless you have a very good reason.
+ // ensure root of new content
+ processCreate(request.getResourceResolver(), reqProperties, response, changes, versioningConfiguration);
- // ensure root of new content
- processCreate(request.getResourceResolver(), reqProperties, response, changes, versioningConfiguration);
+ // write content from existing content (@Move/CopyFrom parameters)
+ processMoves(request.getResourceResolver(), reqProperties, changes, versioningConfiguration);
+ processCopies(request.getResourceResolver(), reqProperties, changes, versioningConfiguration);
- // write content from existing content (@Move/CopyFrom parameters)
- processMoves(request.getResourceResolver(), reqProperties, changes, versioningConfiguration);
- processCopies(request.getResourceResolver(), reqProperties, changes, versioningConfiguration);
+ // cleanup any old content (@Delete parameters)
+ processDeletes(request.getResourceResolver(), reqProperties, changes, versioningConfiguration);
- // cleanup any old content (@Delete parameters)
- processDeletes(request.getResourceResolver(), reqProperties, changes, versioningConfiguration);
+ // write content from form
+ writeContent(request.getResourceResolver(), reqProperties, changes, versioningConfiguration);
- // write content from form
- writeContent(request.getResourceResolver(), reqProperties, changes, versioningConfiguration);
-
- // order content
- final Resource newResource = request.getResourceResolver().getResource(response.getPath());
- this.jcrSsupport.orderNode(request, newResource, changes);
- } catch ( final RepositoryException pe) {
- throw new PersistenceException(pe.getMessage(), pe);
- }
+ // order content
+ final Resource newResource = request.getResourceResolver().getResource(response.getPath());
+ this.jcrSsupport.orderNode(request, newResource, changes);
}
@Override
@@ -180,7 +170,7 @@
private void processMoves(final ResourceResolver resolver,
Map<String, RequestProperty> reqProperties, List<Modification> changes,
VersioningConfiguration versioningConfiguration)
- throws RepositoryException, PersistenceException {
+ throws PersistenceException {
for (RequestProperty property : reqProperties.values()) {
if (property.hasRepositoryMoveSource()) {
@@ -198,7 +188,7 @@
private void processCopies(final ResourceResolver resolver,
Map<String, RequestProperty> reqProperties, List<Modification> changes,
VersioningConfiguration versioningConfiguration)
- throws RepositoryException, PersistenceException {
+ throws PersistenceException {
for (RequestProperty property : reqProperties.values()) {
if (property.hasRepositoryCopySource()) {
@@ -210,8 +200,8 @@
/**
* Internal implementation of the
- * {@link #processCopies(Session, Map, HtmlResponse)} and
- * {@link #processMoves(Session, Map, HtmlResponse)} methods taking into
+ * {@link #processCopies(ResourceResolver, Map, HtmlResponse)} and
+ * {@link #processMoves(ResourceResolver, Map, HtmlResponse)} methods taking into
* account whether the source is actually a property or a node.
* <p>
* Any intermediary nodes to the destination as indicated by the
@@ -222,35 +212,34 @@
* content of the operation.
* @param isMove <code>true</code> if the source item is to be moved.
* Otherwise the source item is just copied.
- * @param session The repository session to use to access the content
+ * @param resolver The resource resolver to use to access the content
* @param reqProperties All accepted request properties. This is used to
* create intermediary nodes along the property path.
- * @param response The <code>HtmlResponse</code> into which successfull
+ * @param response The <code>HtmlResponse</code> into which successful
* copies and moves as well as intermediary node creations are
* recorded.
- * @throws RepositoryException May be thrown if an error occurrs.
+ * @throws PersistenceException May be thrown if an error occurs.
*/
private void processMovesCopiesInternal(
RequestProperty property,
boolean isMove, final ResourceResolver resolver,
Map<String, RequestProperty> reqProperties, List<Modification> changes,
VersioningConfiguration versioningConfiguration)
- throws RepositoryException, PersistenceException {
+ throws PersistenceException {
- final Session session = resolver.adaptTo(Session.class);
String propPath = property.getPath();
String source = property.getRepositorySource();
// only continue here, if the source really exists
- if (session.itemExists(source)) {
+ if (resolver.getResource(source) != null ) {
// if the destination item already exists, remove it
// first, otherwise ensure the parent location
- if (session.itemExists(propPath)) {
- Node parent = session.getItem(propPath).getParent();
- this.jcrSsupport.checkoutIfNecessary(resolver.getResource(parent.getPath()), changes, versioningConfiguration);
+ if (resolver.getResource(propPath) != null) {
+ final Resource parent = resolver.getResource(propPath).getParent();
+ this.jcrSsupport.checkoutIfNecessary(parent, changes, versioningConfiguration);
- session.getItem(propPath).remove();
+ resolver.delete(resolver.getResource(propPath));
changes.add(Modification.onDeleted(propPath));
} else {
Resource parent = deepGetOrCreateResource(resolver, property.getParentPath(),
@@ -259,35 +248,30 @@
}
// move through the session and record operation
- Item sourceItem = session.getItem(source);
- if (sourceItem.isNode()) {
-
- // node move/copy through session
- if (isMove) {
- this.jcrSsupport.checkoutIfNecessary(resolver.getResource(sourceItem.getParent().getPath()), changes, versioningConfiguration);
- session.move(source, propPath);
+ // check if the item is backed by JCR
+ Resource sourceRsrc = resolver.getResource(source);
+ final Object sourceItem = this.jcrSsupport.getItem(sourceRsrc);
+ final Object destItem = this.jcrSsupport.getItem(resolver.getResource(property.getParentPath()));
+ if ( sourceItem != null && destItem != null ) {
+ if ( this.jcrSsupport.isNode(sourceRsrc) ) {
+ if ( isMove ) {
+ this.jcrSsupport.checkoutIfNecessary(sourceRsrc.getParent(), changes, versioningConfiguration);
+ this.jcrSsupport.move(sourceItem, destItem, ResourceUtil.getName(propPath));
+ } else {
+ this.jcrSsupport.checkoutIfNecessary(resolver.getResource(property.getParentPath()), changes, versioningConfiguration);
+ this.jcrSsupport.copy(sourceItem, destItem, property.getName());
+ }
} else {
- Node sourceNode = (Node) sourceItem;
- Node destParent = (Node) session.getItem(property.getParentPath());
- this.jcrSsupport.checkoutIfNecessary(resolver.getResource(destParent.getPath()), changes, versioningConfiguration);
- CopyOperation.copy(sourceNode, destParent,
- property.getName());
- }
+ // property: move manually
+ this.jcrSsupport.checkoutIfNecessary(resolver.getResource(property.getParentPath()), changes, versioningConfiguration);
+ // create destination property
+ this.jcrSsupport.copy(sourceItem, destItem, ResourceUtil.getName(source));
- } else {
-
- // property move manually
- Property sourceProperty = (Property) sourceItem;
-
- // create destination property
- Node destParent = (Node) session.getItem(property.getParentPath());
- this.jcrSsupport.checkoutIfNecessary(resolver.getResource(destParent.getPath()), changes, versioningConfiguration);
- CopyOperation.copy(sourceProperty, destParent, null);
-
- // remove source property (if not just copying)
- if (isMove) {
- this.jcrSsupport.checkoutIfNecessary(resolver.getResource(sourceProperty.getParent().getPath()), changes, versioningConfiguration);
- sourceProperty.remove();
+ // remove source property (if not just copying)
+ if ( isMove ) {
+ this.jcrSsupport.checkoutIfNecessary(sourceRsrc.getParent(), changes, versioningConfiguration);
+ resolver.delete(sourceRsrc);
+ }
}
}
@@ -314,14 +298,14 @@
* properties to be removed.
* @param response The <code>HtmlResponse</code> to be updated with
* information on deleted properties.
- * @throws RepositoryException Is thrown if an error occurrs checking or
+ * @throws PersistenceException Is thrown if an error occurs checking or
* removing properties.
*/
private void processDeletes(final ResourceResolver resolver,
final Map<String, RequestProperty> reqProperties,
final List<Modification> changes,
final VersioningConfiguration versioningConfiguration)
- throws RepositoryException, PersistenceException {
+ throws PersistenceException {
for (final RequestProperty property : reqProperties.values()) {
@@ -330,32 +314,19 @@
if ( parent == null ) {
continue;
}
- final Node parentNode = parent.adaptTo(Node.class);
+ this.jcrSsupport.checkoutIfNecessary(parent, changes, versioningConfiguration);
- if ( parentNode != null ) {
- this.jcrSsupport.checkoutIfNecessary(parent, changes, versioningConfiguration);
-
- if (property.getName().equals("jcr:mixinTypes")) {
-
- // clear all mixins
- for (NodeType mixin : parentNode.getMixinNodeTypes()) {
- parentNode.removeMixin(mixin.getName());
- }
-
- } else {
- if ( parentNode.hasProperty(property.getName())) {
- parentNode.getProperty(property.getName()).remove();
- } else if ( parentNode.hasNode(property.getName())) {
- parentNode.getNode(property.getName()).remove();
- }
- }
-
- } else {
- final ValueMap vm = parent.adaptTo(ModifiableValueMap.class);
- if ( vm == null ) {
- throw new PersistenceException("Resource '" + parent.getPath() + "' is not modifiable.");
- }
+ final ValueMap vm = parent.adaptTo(ModifiableValueMap.class);
+ if ( vm == null ) {
+ throw new PersistenceException("Resource '" + parent.getPath() + "' is not modifiable.");
+ }
+ if ( vm.containsKey(property.getName()) ) {
vm.remove(property.getName());
+ } else {
+ final Resource childRsrc = resolver.getResource(parent.getPath() + '/' + property.getName());
+ if ( childRsrc != null ) {
+ resolver.delete(childRsrc);
+ }
}
changes.add(Modification.onDeleted(property.getPath()));
@@ -367,14 +338,13 @@
/**
* Writes back the content
*
- * @throws RepositoryException if a repository error occurs
* @throws PersistenceException if a persistence error occurs
*/
private void writeContent(final ResourceResolver resolver,
final Map<String, RequestProperty> reqProperties,
final List<Modification> changes,
final VersioningConfiguration versioningConfiguration)
- throws RepositoryException, PersistenceException {
+ throws PersistenceException {
final SlingPropertyValueHandler propHandler = new SlingPropertyValueHandler(
dateParser, this.jcrSsupport, changes);
@@ -387,8 +357,8 @@
this.jcrSsupport.checkoutIfNecessary(parent, changes, versioningConfiguration);
// skip jcr special properties
- if (prop.getName().equals("jcr:primaryType")
- || prop.getName().equals("jcr:mixinTypes")) {
+ if (prop.getName().equals(JcrConstants.JCR_PRIMARYTYPE)
+ || prop.getName().equals(JcrConstants.JCR_MIXINTYPES)) {
continue;
}
diff --git a/src/main/java/org/apache/sling/servlets/post/impl/operations/MoveOperation.java b/src/main/java/org/apache/sling/servlets/post/impl/operations/MoveOperation.java
index eda2acb..a7a804b 100644
--- a/src/main/java/org/apache/sling/servlets/post/impl/operations/MoveOperation.java
+++ b/src/main/java/org/apache/sling/servlets/post/impl/operations/MoveOperation.java
@@ -18,12 +18,9 @@
import java.util.List;
-import javax.jcr.Item;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-
import org.apache.sling.api.resource.PersistenceException;
import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.servlets.post.Modification;
import org.apache.sling.servlets.post.VersioningConfiguration;
@@ -46,37 +43,46 @@
String destName,
final VersioningConfiguration versioningConfiguration)
throws PersistenceException {
- try {
- // ensure we have an item underlying the request's resource
- Item item = source.adaptTo(Item.class);
- if (item == null) {
- return null;
- }
-
- if (destName == null) {
- destName = source.getName();
- }
-
- String sourcePath = source.getPath();
- if (destParent.equals("/")) {
- destParent = "";
- }
- String destPath = destParent + "/" + destName;
- Session session = item.getSession();
-
- this.jcrSsupport.checkoutIfNecessary(source.getParent(), changes, versioningConfiguration);
-
- final Resource dest = source.getResourceResolver().getResource(destPath);
- if (dest != null ) {
- source.getResourceResolver().delete(dest);
- }
-
- session.move(sourcePath, destPath);
- changes.add(Modification.onMoved(sourcePath, destPath));
- return source.getResourceResolver().getResource(destPath);
- } catch ( final RepositoryException re) {
- throw new PersistenceException(re.getMessage(), re);
+ if (destName == null) {
+ destName = source.getName();
}
+
+ if (destParent.equals("/")) {
+ destParent = "";
+ }
+ final String destPath = destParent + "/" + destName;
+
+ final Resource destParentRsrc = source.getResourceResolver().getResource(destParent);
+ final Resource dest = destParentRsrc.getChild(destName);
+ if (dest != null ) {
+ source.getResourceResolver().delete(dest);
+ }
+
+ // ensure we have an item underlying the request's resource
+ final Object item = this.jcrSsupport.getItem(source);
+ final Object target = this.jcrSsupport.getNode(destParentRsrc);
+ if (item == null || target == null ) {
+ move(source, destParentRsrc);
+ } else {
+ this.jcrSsupport.checkoutIfNecessary(source.getParent(), changes, versioningConfiguration);
+ this.jcrSsupport.move(item, target, destName);
+ }
+ changes.add(Modification.onMoved(source.getPath(), destPath));
+ return source.getResourceResolver().getResource(destPath);
}
+ /**
+ * Move the source as a child resource to the parent
+ */
+ private void move(final Resource source, final Resource dest)
+ throws PersistenceException {
+ // first copy
+ final ValueMap vm = source.getValueMap();
+ final Resource result = source.getResourceResolver().create(dest, source.getName(), vm);
+ for(final Resource c : source.getChildren()) {
+ move(c, result);
+ }
+ // then delete
+ source.getResourceResolver().delete(source);
+ }
}
diff --git a/src/test/java/org/apache/sling/servlets/post/impl/operations/CopyOperationTest.java b/src/test/java/org/apache/sling/servlets/post/impl/operations/CopyOperationTest.java
index 4e3fa9d..dca13aa 100644
--- a/src/test/java/org/apache/sling/servlets/post/impl/operations/CopyOperationTest.java
+++ b/src/test/java/org/apache/sling/servlets/post/impl/operations/CopyOperationTest.java
@@ -21,8 +21,7 @@
import javax.jcr.Node;
import javax.jcr.RepositoryException;
-import junit.framework.TestCase;
-
+import org.apache.sling.servlets.post.impl.helper.JCRSupportImpl;
import org.jmock.Expectations;
import org.jmock.Mockery;
import org.jmock.integration.junit4.JMock;
@@ -30,16 +29,18 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import junit.framework.TestCase;
+
@RunWith(JMock.class)
public class CopyOperationTest extends TestCase {
private Mockery context = new JUnit4Mockery();
private int counter;
-
+
private void assertResult(final String srcPath, final String destPath, Boolean expectedResult) throws RepositoryException {
counter++;
final Node src = context.mock(Node.class, "src" + counter);
final Node dest = context.mock(Node.class, "dest" + counter);
-
+
context.checking(new Expectations() {
{
allowing(src).getPath();
@@ -49,12 +50,12 @@
}
});
- final boolean result = CopyOperation.isAncestorOrSameNode(src, dest);
+ final boolean result = JCRSupportImpl.isAncestorOrSameNode(src, dest);
assertEquals(
"Expecting isAncestorOrSameNode to be " + expectedResult + " for " + srcPath + " and " + destPath,
expectedResult.booleanValue(), result);
}
-
+
@Test
public void testIsAncestorOrSameNode() throws RepositoryException {
final Object [] testCases = {
@@ -68,10 +69,10 @@
"/ab/cd", "/ab/cde", false,
"/ab", "/cd", false,
};
-
+
for(int i=0; i < testCases.length; i+=3) {
assertResult((String)testCases[i], (String)testCases[i+1], (Boolean)(testCases[i+2]));
}
-
+
}
}
\ No newline at end of file