ROP server side validation

View: New views
1 Messages — Rating Filter:   Alert me  

ROP server side validation

by Marcin Skladaniec-3 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi

Few thoughts.
For ROP it would be good if some object validation was performed  
locally (field not null, in proper format etc.), yet some validation  
is much better performed on server (duplicate detection, related  
objects validation etc.).
I have looked at this problem and I found a problem : if client  
validation passes and server fails then on the server a  
ValidationException is created. This is good, but on its way to client  
the exception is toStringed() and looses its properties, becomes  
useless on client.

I have looked at this issue and came up with a patch (see bottom of  
the email). What I've done is not even close to "nice" but it works.  
Please tell me if you have a better idea on how to solve it, I can  
implement it and send another patch.

Another problem is that the "mandatory" flags set in cayenne modeller  
are not respected in client validation (basically client side  
validation does nothing by default). Is there a JIRA for this ?

With regards
Marcin


Index: framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/
cayenne/remote/hessian/service/HessianService.java
===================================================================
--- framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/
cayenne/remote/hessian/service/HessianService.java (revision 673550)
+++ framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/
cayenne/remote/hessian/service/HessianService.java (working copy)
@@ -19,6 +19,7 @@

  package org.apache.cayenne.remote.hessian.service;

+import java.io.ByteArrayOutputStream;
  import java.util.Enumeration;
  import java.util.HashMap;
  import java.util.Map;
@@ -32,6 +33,8 @@
  import org.apache.cayenne.remote.hessian.HessianConfig;
  import org.apache.cayenne.remote.service.HttpRemoteService;

+import com.caucho.hessian.io.BasicSerializer;
+import com.caucho.hessian.io.Hessian2Output;
  import com.caucho.hessian.io.SerializerFactory;
  import com.caucho.services.server.Service;
  import com.caucho.services.server.ServiceContext;
@@ -89,4 +92,15 @@
      public void destroy() {
          destroyService();
      }
+
+    @Override
+    public boolean isThrowableSerialisable(Throwable th) {
+        //this is a ugly hack, but how otherwise check if the  
serialisation will succeed?
+        try {
+            
createSerializerFactory().getSerializer(th.getClass()).writeObject(th,  
new Hessian2Output(new ByteArrayOutputStream()));
+        return true;
+        } catch (Throwable error){
+            return false;
+        }
+    }
  }
Index: framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/
cayenne/remote/service/BaseRemoteService.java
===================================================================
--- framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/
cayenne/remote/service/BaseRemoteService.java (revision 673550)
+++ framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/
cayenne/remote/service/BaseRemoteService.java (working copy)
@@ -20,7 +20,9 @@
  package org.apache.cayenne.remote.service;

  import java.io.ByteArrayOutputStream;
+import java.io.ObjectOutputStream;
  import java.io.PrintWriter;
+import java.io.Serializable;
  import java.util.Collections;
  import java.util.HashMap;
  import java.util.Map;
@@ -38,6 +40,9 @@
  import org.apache.commons.logging.Log;
  import org.apache.commons.logging.LogFactory;

+import com.caucho.hessian.io.BasicSerializer;
+import com.caucho.hessian.io.Hessian2Output;
+
  /**
   * A generic implementation of an RemoteService. Subclasses can be  
customized to work with
   * different remoting mechanisms, such as Hessian or JAXRPC.
@@ -156,19 +161,34 @@
              th = Util.unwindException(th);
              logObj.info("error processing message", th);

-            // This exception will probably be propagated to the  
client.
-            // Recast the exception to a serializable form.
-            Exception cause = new Exception(th.getLocalizedMessage());
-
              StringBuilder wrapperMessage = new StringBuilder();
              wrapperMessage.append("Exception processing message ")
                  .append(message.getClass().getName())
                  .append(" of type ").append(message.toString());

+            // This exception will probably be propagated to the  
client.
+            // if the exception should be passed as is (to allow for  
example validation), but unfortunatelly some exceptions (or their  
causes) are not serialisable, for example SQLException thrown by derby
+            if (isThrowableSerialisable(th)) {
+                throw new  
CayenneRuntimeException(wrapperMessage.toString(), th);
+            }
+            // if the exception cannot be serialised recast the  
toString-ed exception.
+            Exception cause = new Exception(th.getClass() + " "  
+th.getLocalizedMessage());
              throw new  
CayenneRuntimeException(wrapperMessage.toString(), cause);
          }
      }
-
+
+    /**
+     * An ugly check if the throwable can be serialised.
+     */
+    public boolean isThrowableSerialisable(Throwable th) {
+        try {
+            new ObjectOutputStream(new  
ByteArrayOutputStream()).writeObject(th);
+        return true;
+        } catch (Throwable error){
+            return false;
+        }
+    }
+
      protected RemoteSession createRemoteSession(
              String sessionId,
              String name,