You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ro...@apache.org on 2021/01/12 13:11:43 UTC

[sling-org-apache-sling-servlets-post] branch master updated: SLING-9896 - Make exception handling more granular

This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-servlets-post.git


The following commit(s) were added to refs/heads/master by this push:
     new d843c5d  SLING-9896 - Make exception handling more granular
d843c5d is described below

commit d843c5dd34aa77727a155652b10229d1445c0e17
Author: Jörg Hoh <jo...@users.noreply.github.com>
AuthorDate: Tue Jan 12 14:11:38 2021 +0100

    SLING-9896 - Make exception handling more granular
---
 .../sling/servlets/post/AbstractPostOperation.java |  8 ++-
 .../servlets/post/AbstractSlingPostOperation.java  |  4 +-
 .../apache/sling/servlets/post/PostOperation.java  |  4 +-
 .../sling/servlets/post/SlingPostOperation.java    | 11 +++-
 .../PreconditionViolatedPersistenceException.java  | 48 +++++++++++++++
 .../exceptions/TemporaryPersistenceException.java  | 47 +++++++++++++++
 .../post/impl/PostOperationProxyProvider.java      |  4 +-
 .../sling/servlets/post/impl/SlingPostServlet.java | 33 +++++++++-
 .../servlets/post/impl/helper/JCRSupportImpl.java  | 70 +++++++++++++++++++---
 .../impl/operations/AbstractPostOperation.java     |  4 +-
 .../post/impl/operations/NopOperation.java         |  4 +-
 .../servlets/post/AbstractPostOperationTest.java   | 10 ++--
 12 files changed, 225 insertions(+), 22 deletions(-)

diff --git a/src/main/java/org/apache/sling/servlets/post/AbstractPostOperation.java b/src/main/java/org/apache/sling/servlets/post/AbstractPostOperation.java
index 135006a..ded1d04 100644
--- a/src/main/java/org/apache/sling/servlets/post/AbstractPostOperation.java
+++ b/src/main/java/org/apache/sling/servlets/post/AbstractPostOperation.java
@@ -40,6 +40,8 @@ import org.apache.sling.api.resource.Resource;
 import org.apache.sling.api.resource.ResourceResolver;
 import org.apache.sling.api.resource.ResourceUtil;
 import org.apache.sling.api.wrappers.SlingRequestPaths;
+import org.apache.sling.servlets.post.exceptions.PreconditionViolatedPersistenceException;
+import org.apache.sling.servlets.post.exceptions.TemporaryPersistenceException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -79,7 +81,7 @@ public abstract class AbstractPostOperation implements PostOperation {
     @Override
     public void run(final SlingHttpServletRequest request,
                     final PostResponse response,
-                    final SlingPostProcessor[] processors) {
+                    final SlingPostProcessor[] processors) throws PreconditionViolatedPersistenceException, TemporaryPersistenceException {
         final Session session = request.getResourceResolver().adaptTo(Session.class);
 
         final VersioningConfiguration versionableConfiguration = getVersioningConfiguration(request);
@@ -212,10 +214,12 @@ public abstract class AbstractPostOperation implements PostOperation {
      *            representing the operations done.
      * @throws RepositoryException Maybe thrown if any error occurrs while
      *             accessing the repository.
+     * @throws TemporaryPersistenceException 
+     * @throws PreconditionViolatedPersistenceException 
      */
     protected abstract void doRun(SlingHttpServletRequest request,
             PostResponse response,
-            List<Modification> changes) throws RepositoryException;
+            List<Modification> changes) throws RepositoryException, PreconditionViolatedPersistenceException, TemporaryPersistenceException;
 
     /**
      * Get the versioning configuration.
diff --git a/src/main/java/org/apache/sling/servlets/post/AbstractSlingPostOperation.java b/src/main/java/org/apache/sling/servlets/post/AbstractSlingPostOperation.java
index 242710d..28b55a8 100644
--- a/src/main/java/org/apache/sling/servlets/post/AbstractSlingPostOperation.java
+++ b/src/main/java/org/apache/sling/servlets/post/AbstractSlingPostOperation.java
@@ -22,6 +22,8 @@ import javax.jcr.RepositoryException;
 
 import org.apache.sling.api.SlingHttpServletRequest;
 import org.apache.sling.api.servlets.HtmlResponse;
+import org.apache.sling.servlets.post.exceptions.PreconditionViolatedPersistenceException;
+import org.apache.sling.servlets.post.exceptions.TemporaryPersistenceException;
 import org.apache.sling.servlets.post.impl.helper.HtmlPostResponseProxy;
 import org.apache.sling.servlets.post.impl.helper.HtmlResponseProxy;
 
@@ -74,7 +76,7 @@ public abstract class AbstractSlingPostOperation extends AbstractPostOperation
      * with a proxy around the Sling API <code>HtmlResponse</code> provided.
      */
     public void run(SlingHttpServletRequest request, HtmlResponse response,
-            SlingPostProcessor[] processors) {
+            SlingPostProcessor[] processors) throws PreconditionViolatedPersistenceException, TemporaryPersistenceException {
         final PostResponse postResponseProxy = new HtmlPostResponseProxy(
             response);
         run(request, postResponseProxy, processors);
diff --git a/src/main/java/org/apache/sling/servlets/post/PostOperation.java b/src/main/java/org/apache/sling/servlets/post/PostOperation.java
index 366a298..e2b42b3 100644
--- a/src/main/java/org/apache/sling/servlets/post/PostOperation.java
+++ b/src/main/java/org/apache/sling/servlets/post/PostOperation.java
@@ -19,6 +19,8 @@
 package org.apache.sling.servlets.post;
 
 import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.servlets.post.exceptions.PreconditionViolatedPersistenceException;
+import org.apache.sling.servlets.post.exceptions.TemporaryPersistenceException;
 
 /**
  * The <code>PostOperation</code> interface defines the service API to be
@@ -81,5 +83,5 @@ public interface PostOperation {
      *             occurrs running the operation.
      */
     void run(SlingHttpServletRequest request, PostResponse response,
-            SlingPostProcessor[] processors);
+            SlingPostProcessor[] processors) throws PreconditionViolatedPersistenceException, TemporaryPersistenceException;
 }
diff --git a/src/main/java/org/apache/sling/servlets/post/SlingPostOperation.java b/src/main/java/org/apache/sling/servlets/post/SlingPostOperation.java
index 4d430cb..3aa490b 100644
--- a/src/main/java/org/apache/sling/servlets/post/SlingPostOperation.java
+++ b/src/main/java/org/apache/sling/servlets/post/SlingPostOperation.java
@@ -20,6 +20,8 @@ package org.apache.sling.servlets.post;
 
 import org.apache.sling.api.SlingHttpServletRequest;
 import org.apache.sling.api.servlets.HtmlResponse;
+import org.apache.sling.servlets.post.exceptions.PreconditionViolatedPersistenceException;
+import org.apache.sling.servlets.post.exceptions.TemporaryPersistenceException;
 
 /**
  * The <code>SlingPostOperation</code> interface defines the service API to be
@@ -69,6 +71,13 @@ public interface SlingPostOperation {
      * @param processors The {@link SlingPostProcessor} services to be called
      *            after applying the operation. This may be <code>null</code> if
      *            there are none.
+     * @throws TemporaryPersistenceException May be thrown if an error occurs during
+     *             the operation, for which it makes sense to retry it with the same
+     *             parameters
+     * @throws PreconditionViolatedPersistenceException May be thrown if an error occurrs
+     *             during the operation because preconditions are not fulfilled.
+     *             If the operation should be repeated with the same parameters, it
+     *             will fail again.
      * @throws org.apache.sling.api.resource.ResourceNotFoundException May be
      *             thrown if the operation requires an existing request
      *             resource. If this exception is thrown the Sling default POST
@@ -78,5 +87,5 @@ public interface SlingPostOperation {
      *             occurrs running the operation.
      */
     void run(SlingHttpServletRequest request, HtmlResponse response,
-            SlingPostProcessor[] processors);
+            SlingPostProcessor[] processors) throws PreconditionViolatedPersistenceException, TemporaryPersistenceException;
 }
diff --git a/src/main/java/org/apache/sling/servlets/post/exceptions/PreconditionViolatedPersistenceException.java b/src/main/java/org/apache/sling/servlets/post/exceptions/PreconditionViolatedPersistenceException.java
new file mode 100644
index 0000000..459c69e
--- /dev/null
+++ b/src/main/java/org/apache/sling/servlets/post/exceptions/PreconditionViolatedPersistenceException.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.servlets.post.exceptions;
+
+import org.apache.sling.api.resource.PersistenceException;
+
+
+/**
+ *  Indicates that the input does not meet necessary precondition.
+ *  In that case the client should redo the request with a changed input.
+ *
+ */
+
+public class PreconditionViolatedPersistenceException extends PersistenceException {
+
+
+  private static final long serialVersionUID = 1L;
+  
+  public PreconditionViolatedPersistenceException(String message, Exception e) {
+    super(message, e);
+  }
+  
+  public PreconditionViolatedPersistenceException(final String msg,
+          final Throwable cause,
+          final String resourcePath,
+          final String propertyName) {
+            super(msg,cause,resourcePath,propertyName);
+            
+            }
+  
+
+}
diff --git a/src/main/java/org/apache/sling/servlets/post/exceptions/TemporaryPersistenceException.java b/src/main/java/org/apache/sling/servlets/post/exceptions/TemporaryPersistenceException.java
new file mode 100644
index 0000000..a8bc2c1
--- /dev/null
+++ b/src/main/java/org/apache/sling/servlets/post/exceptions/TemporaryPersistenceException.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.servlets.post.exceptions;
+
+import org.apache.sling.api.resource.PersistenceException;
+
+
+/**
+ * This exceptions indicates errors, which might be temporary and for which a retry
+ * with the same parameters could work.
+ *
+ */
+public class TemporaryPersistenceException extends PersistenceException {
+
+
+    private static final long serialVersionUID = 8922639484264855481L;
+
+    public TemporaryPersistenceException(String message, Exception e) {
+        super(message, e);
+    }
+  
+    public TemporaryPersistenceException(final String msg,
+          final Throwable cause,
+          final String resourcePath,
+          final String propertyName) {
+            super(msg,cause,resourcePath,propertyName);
+            
+            }
+
+
+}
diff --git a/src/main/java/org/apache/sling/servlets/post/impl/PostOperationProxyProvider.java b/src/main/java/org/apache/sling/servlets/post/impl/PostOperationProxyProvider.java
index 5ad331d..a394dc8 100644
--- a/src/main/java/org/apache/sling/servlets/post/impl/PostOperationProxyProvider.java
+++ b/src/main/java/org/apache/sling/servlets/post/impl/PostOperationProxyProvider.java
@@ -29,6 +29,8 @@ import org.apache.sling.servlets.post.PostOperation;
 import org.apache.sling.servlets.post.PostResponse;
 import org.apache.sling.servlets.post.SlingPostOperation;
 import org.apache.sling.servlets.post.SlingPostProcessor;
+import org.apache.sling.servlets.post.exceptions.PreconditionViolatedPersistenceException;
+import org.apache.sling.servlets.post.exceptions.TemporaryPersistenceException;
 import org.apache.sling.servlets.post.impl.helper.HtmlResponseProxy;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.Constants;
@@ -246,7 +248,7 @@ public class PostOperationProxyProvider implements ServiceListener {
 
         @Override
         public void run(SlingHttpServletRequest request, PostResponse response,
-                SlingPostProcessor[] processors) {
+                SlingPostProcessor[] processors) throws PreconditionViolatedPersistenceException, TemporaryPersistenceException {
             HtmlResponse apiResponse = new HtmlResponseProxy(response);
             delegatee.run(request, apiResponse, processors);
         }
diff --git a/src/main/java/org/apache/sling/servlets/post/impl/SlingPostServlet.java b/src/main/java/org/apache/sling/servlets/post/impl/SlingPostServlet.java
index 41608fe..081deb2 100644
--- a/src/main/java/org/apache/sling/servlets/post/impl/SlingPostServlet.java
+++ b/src/main/java/org/apache/sling/servlets/post/impl/SlingPostServlet.java
@@ -34,6 +34,7 @@ import javax.servlet.http.HttpServletResponse;
 
 import org.apache.sling.api.SlingHttpServletRequest;
 import org.apache.sling.api.SlingHttpServletResponse;
+import org.apache.sling.api.resource.PersistenceException;
 import org.apache.sling.api.request.header.MediaRangeList;
 import org.apache.sling.api.resource.ResourceNotFoundException;
 import org.apache.sling.api.resource.ResourceUtil;
@@ -48,6 +49,8 @@ import org.apache.sling.servlets.post.PostResponseCreator;
 import org.apache.sling.servlets.post.SlingPostConstants;
 import org.apache.sling.servlets.post.SlingPostProcessor;
 import org.apache.sling.servlets.post.VersioningConfiguration;
+import org.apache.sling.servlets.post.exceptions.PreconditionViolatedPersistenceException;
+import org.apache.sling.servlets.post.exceptions.TemporaryPersistenceException;
 import org.apache.sling.servlets.post.impl.helper.DateParser;
 import org.apache.sling.servlets.post.impl.helper.DefaultNodeNameGenerator;
 import org.apache.sling.servlets.post.impl.helper.JCRSupport;
@@ -151,6 +154,11 @@ public class SlingPostServlet extends SlingAllMethodsServlet {
                             "content to the repository. By default this is \"j_.*\" thus ignoring all "+
                             "request parameters starting with j_ such as j_username.")
         String servlet_post_ignorePattern() default "j_.*";
+        
+        @AttributeDefinition(name="Backwards compatible statuscode",
+                description="In backwards compatibility mode exceptions will always create a statuscode "
+                    + "500 (see SLING-9896)")
+        boolean legacy_statuscode_on_persistence_exception() default false;
     }
 
     /**
@@ -194,6 +202,8 @@ public class SlingPostServlet extends SlingAllMethodsServlet {
     private VersioningConfiguration baseVersioningConfiguration;
 
     private ImportOperation importOperation;
+    
+    private boolean backwardsCompatibleStatuscode;
 
     public SlingPostServlet() {
         // the following operations require JCR:
@@ -234,10 +244,26 @@ public class SlingPostServlet extends SlingAllMethodsServlet {
             } catch (ResourceNotFoundException rnfe) {
                 htmlResponse.setStatus(HttpServletResponse.SC_NOT_FOUND,
                     rnfe.getMessage());
+            } catch (final PreconditionViolatedPersistenceException e) {
+                log.warn("Exception while handling POST {} with {}",
+                        new Object[] {request.getResource().getPath(),operation.getClass().getName()},e);
+                if (backwardsCompatibleStatuscode) {
+                    htmlResponse.setError(e);
+                } else {
+                    htmlResponse.setStatus(422, "invalid payload");
+                }
+            } catch (final PersistenceException e) {
+                // also catches the  RetryableOperationException, as the handling is the same
+                log.warn("Exception while handling POST {} with {}",
+                        new Object[] {request.getResource().getPath(),operation.getClass().getName()},e);
+                if (backwardsCompatibleStatuscode) {
+                    htmlResponse.setError(e);
+                } else {
+                    htmlResponse.setStatus(HttpServletResponse.SC_CONFLICT, "repository state conflicting with request");
+                }
             } catch (final Exception exception) {
-                log.warn("Exception while handling POST "
-                    + request.getResource().getPath() + " with "
-                    + operation.getClass().getName(), exception);
+                log.warn("Exception while handling POST {} with {}",
+                        new Object[] {request.getResource().getPath(),operation.getClass().getName()},exception);
                 htmlResponse.setError(exception);
             }
 
@@ -507,6 +533,7 @@ public class SlingPostServlet extends SlingAllMethodsServlet {
             this.importOperation.setDefaultNodeNameGenerator(nodeNameGenerator);
             this.importOperation.setIgnoredParameterNamePattern(paramMatchPattern);
         }
+        this.backwardsCompatibleStatuscode = configuration.legacy_statuscode_on_persistence_exception();
     }
 
     @Override
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 724928f..e0f89d1 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,19 +20,29 @@ package org.apache.sling.servlets.post.impl.helper;
 
 import java.util.List;
 
+import javax.jcr.AccessDeniedException;
+import javax.jcr.InvalidItemStateException;
 import javax.jcr.Item;
+import javax.jcr.ItemExistsException;
 import javax.jcr.ItemNotFoundException;
 import javax.jcr.Node;
 import javax.jcr.NodeIterator;
+import javax.jcr.PathNotFoundException;
 import javax.jcr.Property;
 import javax.jcr.PropertyIterator;
 import javax.jcr.PropertyType;
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
+import javax.jcr.UnsupportedRepositoryOperationException;
 import javax.jcr.Value;
+import javax.jcr.ValueFormatException;
+import javax.jcr.lock.LockException;
+import javax.jcr.nodetype.ConstraintViolationException;
+import javax.jcr.nodetype.NoSuchNodeTypeException;
 import javax.jcr.nodetype.NodeType;
 import javax.jcr.nodetype.NodeTypeManager;
 import javax.jcr.nodetype.PropertyDefinition;
+import javax.jcr.version.VersionException;
 
 import org.apache.jackrabbit.JcrConstants;
 import org.apache.sling.api.SlingHttpServletRequest;
@@ -42,6 +52,8 @@ import org.apache.sling.api.resource.ResourceResolver;
 import org.apache.sling.servlets.post.Modification;
 import org.apache.sling.servlets.post.SlingPostConstants;
 import org.apache.sling.servlets.post.VersioningConfiguration;
+import org.apache.sling.servlets.post.exceptions.PreconditionViolatedPersistenceException;
+import org.apache.sling.servlets.post.exceptions.TemporaryPersistenceException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -60,6 +72,8 @@ public class JCRSupportImpl {
      * @param item node to order
      * @param changes The list of modifications
      * @throws RepositoryException if an error occurs
+     * @throws PreconditionViolatedPersistenceException 
+     * @throws TemporaryPersistenceException 
      */
     public void orderNode(final SlingHttpServletRequest request,
             final Resource resource,
@@ -149,6 +163,10 @@ public class JCRSupportImpl {
                 throw new IllegalArgumentException(
                     "provided node ordering command is invalid: " + command);
             }
+        } catch (final VersionException|ConstraintViolationException|ItemNotFoundException e) {
+            throw new PreconditionViolatedPersistenceException("Unable to order resource", e, resource.getPath(), null);
+        } catch (final UnsupportedRepositoryOperationException|LockException e) { 
+            throw new TemporaryPersistenceException("Unable to order resource", e, resource.getPath(), null);
         } catch ( final RepositoryException re) {
             throw new PersistenceException("Unable to order resource", re, resource.getPath(), null);
         }
@@ -176,6 +194,10 @@ public class JCRSupportImpl {
                     node.getSession().getWorkspace().getVersionManager().checkin(node.getPath());
                     return true;
                 }
+            } catch (final AccessDeniedException e) {
+                throw new PreconditionViolatedPersistenceException(e.getMessage(), e, rsrc.getPath(), null);
+            } catch (final UnsupportedRepositoryOperationException|InvalidItemStateException|LockException e) { 
+                throw new TemporaryPersistenceException(e.getMessage(), e, rsrc.getPath(), null);
             } catch ( final RepositoryException re) {
                 throw new PersistenceException(re.getMessage(), re, rsrc.getPath(), null);
             }
@@ -211,7 +233,11 @@ public class JCRSupportImpl {
                             changes.add(Modification.onCheckout(versionableNode.getPath()));
                         }
                     }
-                } catch ( final RepositoryException re) {
+                } catch (final AccessDeniedException e) {
+                    throw new PreconditionViolatedPersistenceException(e.getMessage(),e);
+                } catch (final UnsupportedRepositoryOperationException e) { 
+                    throw new TemporaryPersistenceException(e.getMessage(),e);
+                } catch (final RepositoryException re) {
                     throw new PersistenceException(re.getMessage(), re);
                 }
             }
@@ -305,6 +331,8 @@ public class JCRSupportImpl {
         try {
             final Property prop = ((Node)node).getProperty(name);
             return prop.getDefinition().isMandatory();
+        } catch (final PathNotFoundException e) {
+            throw new PreconditionViolatedPersistenceException(e.getMessage(),e);
         } catch ( final RepositoryException re) {
             throw new PersistenceException(re.getMessage(), re);
         }
@@ -315,6 +343,8 @@ public class JCRSupportImpl {
         try {
             final Property prop = ((Node)node).getProperty(name);
             return prop.getDefinition().isMultiple();
+        } catch (final PathNotFoundException e) {
+            throw new PreconditionViolatedPersistenceException(e.getMessage(),e);
         } catch ( final RepositoryException re) {
             throw new PersistenceException(re.getMessage(), re);
         }
@@ -326,7 +356,11 @@ public class JCRSupportImpl {
             if ( ((Node)node).hasProperty(name) ) {
                 return ((Node)node).getProperty(name).getType();
             }
-        } catch ( final RepositoryException re) {
+        } catch (final NoSuchNodeTypeException|ConstraintViolationException|PathNotFoundException e) {
+            throw new PreconditionViolatedPersistenceException(e.getMessage(),e);
+        } catch (final VersionException|LockException e) { 
+            throw new TemporaryPersistenceException(e.getMessage(),e);
+        } catch (final RepositoryException re) {
             throw new PersistenceException(re.getMessage(), re);
         }
         return null;
@@ -367,7 +401,11 @@ public class JCRSupportImpl {
                 }
             }
             return null;
-        } catch ( final RepositoryException re) {
+        } catch (final NoSuchNodeTypeException|ConstraintViolationException e) {
+            throw new PreconditionViolatedPersistenceException(e.getMessage(),e);
+        } catch (final VersionException|LockException e) { 
+            throw new TemporaryPersistenceException(e.getMessage(),e);
+        } catch (final RepositoryException re) {
             throw new PersistenceException(re.getMessage(), re);
         }
     }
@@ -388,7 +426,11 @@ public class JCRSupportImpl {
             } else if (values.length >= 1) {
                 ((Node)n).setProperty(name, values[0], type);
             }
-        } catch ( final RepositoryException re) {
+        } catch (final ValueFormatException|ConstraintViolationException e) {
+            throw new PreconditionViolatedPersistenceException(e.getMessage(),e);
+        } catch (final VersionException|LockException e) { 
+            throw new TemporaryPersistenceException(e.getMessage(),e);
+        } catch (final RepositoryException re) {
             throw new PersistenceException(re.getMessage(), re);
         }
     }
@@ -405,7 +447,11 @@ public class JCRSupportImpl {
     throws PersistenceException {
         try {
             ((Node)node).setPrimaryType(type);
-        } catch ( final RepositoryException re) {
+        } catch (final NoSuchNodeTypeException|ConstraintViolationException e) {
+            throw new PreconditionViolatedPersistenceException(e.getMessage(),e);
+        } catch (final VersionException|LockException e) { 
+            throw new TemporaryPersistenceException(e.getMessage(),e);
+        } catch (final RepositoryException re) {
             throw new PersistenceException(re.getMessage(), re);
         }
     }
@@ -418,7 +464,11 @@ public class JCRSupportImpl {
             final String targetParentPath = ((Node)dstParent).getPath();
             final String targetPath = (targetParentPath.equals("/") ? "" : targetParentPath) + '/' + name;
             session.move(source.getPath(), targetPath);
-        } catch ( final RepositoryException re) {
+        } catch (final PathNotFoundException|ConstraintViolationException|ItemExistsException e) {
+            throw new PreconditionViolatedPersistenceException(e.getMessage(),e);
+        } catch (final VersionException|LockException e) { 
+            throw new TemporaryPersistenceException(e.getMessage(),e);
+        } catch (final RepositoryException re) {
             throw new PersistenceException(re.getMessage(), re);
         }
     }
@@ -435,6 +485,8 @@ public class JCRSupportImpl {
      *            <code>src</code> item.
      * @throws PersistenceException May be thrown in case of any problem copying
      *             the content.
+     * @throws PreconditionViolatedPersistenceException 
+     * @throws TemporaryPersistenceException
      * @see #copy(Node, Node, String)
      * @see #copy(Property, Node, String)
      */
@@ -448,7 +500,11 @@ public class JCRSupportImpl {
                 result = copy((Property) src, (Node)dstParent, name);
             }
             return result.getPath();
-        } catch ( final RepositoryException re) {
+        } catch (final NoSuchNodeTypeException|ConstraintViolationException e) {
+            throw new PreconditionViolatedPersistenceException(e.getMessage(),e);
+        } catch (final VersionException|LockException e) { 
+            throw new TemporaryPersistenceException(e.getMessage(),e);
+        } catch (final RepositoryException re) {
             throw new PersistenceException(re.getMessage(), re);
         }
     }
diff --git a/src/main/java/org/apache/sling/servlets/post/impl/operations/AbstractPostOperation.java b/src/main/java/org/apache/sling/servlets/post/impl/operations/AbstractPostOperation.java
index b5d42eb..493bf71 100644
--- a/src/main/java/org/apache/sling/servlets/post/impl/operations/AbstractPostOperation.java
+++ b/src/main/java/org/apache/sling/servlets/post/impl/operations/AbstractPostOperation.java
@@ -40,6 +40,8 @@ import org.apache.sling.servlets.post.PostResponse;
 import org.apache.sling.servlets.post.SlingPostConstants;
 import org.apache.sling.servlets.post.SlingPostProcessor;
 import org.apache.sling.servlets.post.VersioningConfiguration;
+import org.apache.sling.servlets.post.exceptions.PreconditionViolatedPersistenceException;
+import org.apache.sling.servlets.post.exceptions.TemporaryPersistenceException;
 import org.apache.sling.servlets.post.impl.helper.JCRSupport;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -81,7 +83,7 @@ public abstract class AbstractPostOperation implements PostOperation {
     @Override
     public void run(final SlingHttpServletRequest request,
                     final PostResponse response,
-                    final SlingPostProcessor[] processors) {
+                    final SlingPostProcessor[] processors) throws PreconditionViolatedPersistenceException, TemporaryPersistenceException {
         final VersioningConfiguration versionableConfiguration = getVersioningConfiguration(request);
 
         try {
diff --git a/src/main/java/org/apache/sling/servlets/post/impl/operations/NopOperation.java b/src/main/java/org/apache/sling/servlets/post/impl/operations/NopOperation.java
index eceb8d0..64a611d 100644
--- a/src/main/java/org/apache/sling/servlets/post/impl/operations/NopOperation.java
+++ b/src/main/java/org/apache/sling/servlets/post/impl/operations/NopOperation.java
@@ -23,6 +23,8 @@ import org.apache.sling.servlets.post.PostOperation;
 import org.apache.sling.servlets.post.PostResponse;
 import org.apache.sling.servlets.post.SlingPostConstants;
 import org.apache.sling.servlets.post.SlingPostProcessor;
+import org.apache.sling.servlets.post.exceptions.PreconditionViolatedPersistenceException;
+import org.apache.sling.servlets.post.exceptions.TemporaryPersistenceException;
 
 /**
  * The <code>NopOperation</code> class implements no operation at all. It just
@@ -33,7 +35,7 @@ public class NopOperation implements PostOperation {
 
     @Override
     public void run(SlingHttpServletRequest request, PostResponse response,
-            SlingPostProcessor[] processors) {
+            SlingPostProcessor[] processors) throws PreconditionViolatedPersistenceException, TemporaryPersistenceException {
 
         // get the :nopstatus parameter for a specific code
         int status = SlingPostConstants.NOPSTATUS_VALUE_DEFAULT;
diff --git a/src/test/java/org/apache/sling/servlets/post/AbstractPostOperationTest.java b/src/test/java/org/apache/sling/servlets/post/AbstractPostOperationTest.java
index 832839a..65280b5 100644
--- a/src/test/java/org/apache/sling/servlets/post/AbstractPostOperationTest.java
+++ b/src/test/java/org/apache/sling/servlets/post/AbstractPostOperationTest.java
@@ -18,6 +18,8 @@ package org.apache.sling.servlets.post;
 
 import org.apache.sling.api.SlingHttpServletRequest;
 import org.apache.sling.commons.testing.sling.MockResourceResolver;
+import org.apache.sling.servlets.post.exceptions.PreconditionViolatedPersistenceException;
+import org.apache.sling.servlets.post.exceptions.TemporaryPersistenceException;
 import org.apache.sling.servlets.post.impl.helper.MockSlingHttpServlet3Request;
 import org.junit.Test;
 
@@ -30,7 +32,7 @@ import static org.junit.Assert.*;
 public class AbstractPostOperationTest {
 
     @Test
-    public void testRemainingPostfixCausesFailure() {
+    public void testRemainingPostfixCausesFailure() throws Exception {
         TestingResourceResolver resourceResolver = new TestingResourceResolver();
 
         MockSlingHttpServlet3Request request = new MockSlingHttpServlet3Request("/test", null, null, null, null);
@@ -38,7 +40,7 @@ public class AbstractPostOperationTest {
 
         final PostOperation operation = new AbstractPostOperation() {
             @Override
-            protected void doRun(SlingHttpServletRequest request, PostResponse response, List<Modification> changes) throws RepositoryException {
+            protected void doRun(SlingHttpServletRequest request, PostResponse response, List<Modification> changes) throws RepositoryException, PreconditionViolatedPersistenceException, TemporaryPersistenceException {
                 changes.add(Modification.onChange(ModificationType.CREATE, "/content/test"));
                 changes.add(Modification.onChange(ModificationType.CREATE, "/content/test@Postfix"));
             }
@@ -52,7 +54,7 @@ public class AbstractPostOperationTest {
     }
 
     @Test
-    public void testNoRemainingPostfixIsSuccessful() {
+    public void testNoRemainingPostfixIsSuccessful() throws Exception {
         TestingResourceResolver resourceResolver = new TestingResourceResolver();
 
         MockSlingHttpServlet3Request request = new MockSlingHttpServlet3Request("/test", null, null, null, null);
@@ -73,7 +75,7 @@ public class AbstractPostOperationTest {
     }
 
     @Test
-    public void testRemainingPostfixWithoutUnPostfixedIsSuccessful() {
+    public void testRemainingPostfixWithoutUnPostfixedIsSuccessful() throws Exception {
         TestingResourceResolver resourceResolver = new TestingResourceResolver();
 
         MockSlingHttpServlet3Request request = new MockSlingHttpServlet3Request("/test", null, null, null, null);