Alexander Wels has uploaded a new change for review.

Change subject: engine: Hibernate PersistentCollections
......................................................................

engine: Hibernate PersistentCollections

- Replace all hibernate AbstractPersistentCollections with
  their equivalent simple java collections before transmitting
  the object to the GWT frontend.

Change-Id: I4eac0864e844ad8e1885134df69f976c784b3960
Signed-off-by: Alexander Wels <aw...@redhat.com>
---
M 
frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/server/gwt/GenericApiGWTServiceImpl.java
A 
frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/server/gwt/hibernate/HibernateCleaner.java
A 
frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/server/gwt/hibernate/ReflectionUtils.java
D 
frontend/webadmin/modules/gwt-extension/src/main/java/org/ovirt/engine/ui/uioverrides/org/hibernate/collection/internal/PersistentBag.java
4 files changed, 253 insertions(+), 14 deletions(-)


  git pull ssh://gerrit.ovirt.org:29418/ovirt-engine refs/changes/10/41810/1

diff --git 
a/frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/server/gwt/GenericApiGWTServiceImpl.java
 
b/frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/server/gwt/GenericApiGWTServiceImpl.java
index bd03c3a..a253446 100644
--- 
a/frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/server/gwt/GenericApiGWTServiceImpl.java
+++ 
b/frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/server/gwt/GenericApiGWTServiceImpl.java
@@ -2,11 +2,13 @@
 
 import java.util.ArrayList;
 import java.util.Random;
+
 import javax.ejb.EJB;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpSession;
 
 import com.google.gwt.user.client.rpc.SerializationException;
+
 import org.ovirt.engine.core.common.action.LoginUserParameters;
 import org.ovirt.engine.core.common.action.VdcActionParametersBase;
 import org.ovirt.engine.core.common.action.VdcActionType;
@@ -19,6 +21,7 @@
 import org.ovirt.engine.core.common.queries.VdcQueryReturnValue;
 import org.ovirt.engine.core.common.queries.VdcQueryType;
 import org.ovirt.engine.ui.frontend.gwtservices.GenericApiGWTService;
+import org.ovirt.engine.ui.frontend.server.gwt.hibernate.HibernateCleaner;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -51,7 +54,9 @@
         log.debug("Server: RunQuery invoked!"); //$NON-NLS-1$
         debugQuery(search, searchParameters);
         searchParameters.setSessionId(getEngineSessionId());
-        return getBackend().runQuery(search, searchParameters);
+        VdcQueryReturnValue returnValue = getBackend().runQuery(search, 
searchParameters);
+        
returnValue.setReturnValue(HibernateCleaner.doClean(returnValue.getReturnValue()));
+        return returnValue;
     }
 
     @Override
@@ -59,7 +64,9 @@
             VdcQueryParametersBase params) {
         log.debug("Server: runPublicQuery invoked! '{}'", queryType); 
//$NON-NLS-1$
         debugQuery(queryType, params);
-        return getBackend().runPublicQuery(queryType, params);
+        VdcQueryReturnValue returnValue = 
getBackend().runPublicQuery(queryType, params);
+        returnValue = (VdcQueryReturnValue) 
HibernateCleaner.doClean(returnValue);
+        return returnValue;
     }
 
     @Override
diff --git 
a/frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/server/gwt/hibernate/HibernateCleaner.java
 
b/frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/server/gwt/hibernate/HibernateCleaner.java
new file mode 100644
index 0000000..9ab7f8b
--- /dev/null
+++ 
b/frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/server/gwt/hibernate/HibernateCleaner.java
@@ -0,0 +1,177 @@
+package org.ovirt.engine.ui.frontend.server.gwt.hibernate;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.hibernate.collection.internal.AbstractPersistentCollection;
+import org.hibernate.collection.internal.PersistentBag;
+import org.hibernate.collection.internal.PersistentList;
+import org.hibernate.collection.internal.PersistentMap;
+import org.hibernate.collection.internal.PersistentSet;
+import org.hibernate.collection.internal.PersistentSortedSet;
+import org.hibernate.proxy.HibernateProxy;
+import org.hibernate.proxy.LazyInitializer;
+
+public class HibernateCleaner {
+
+    public static Object doClean(Object dirty) {
+        return doClean(dirty, null);
+    }
+
+    private static Object doClean(Object dirty, Map<Object, Object> processed) 
{
+        if (dirty == null) {
+            return null;
+        }
+
+        if (processed == null) {
+            processed = new HashMap<>();
+        }
+
+        if (processed.get(dirty) != null) {
+            return processed.get(dirty);
+        }
+
+        if (isPrimitive(dirty)) {
+            return dirty;
+        }
+
+        if (!processCollections(dirty, processed)) {
+            for (String getterName : ReflectionUtils.getGetterNames(dirty)) {
+                Object object = ReflectionUtils.get(dirty, getterName);
+                if (object instanceof AbstractPersistentCollection) {
+                    // Hibernate persistent class, replace the implementation.
+                    ReflectionUtils.setIfPossible(dirty, getterName, 
doHibernateClean(object, processed));
+                } else {
+                    processed.put(dirty, dirty);
+                    doClean(object, processed);
+                }
+            }
+        }
+        return dirty;
+    }
+
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    private static boolean processCollections(Object dirty, Map<Object, 
Object> processed) {
+        if (dirty instanceof List) {
+            for (Object value : (List) dirty) {
+                doClean(value, processed);
+            }
+            return true;
+        } else if (dirty instanceof Map) {
+            for (Map.Entry<Object, Object> entry : ((Map<Object, Object>) 
dirty).entrySet()) {
+                doClean(entry.getKey(), processed);
+                doClean(entry.getValue(), processed);
+            }
+            return true;
+        } else if (dirty instanceof Set) {
+            for (Object value : (Set<Object>) dirty) {
+                doClean(value, processed);
+            }
+            return true;
+        } else if (dirty instanceof HibernateProxy) {
+            HibernateProxy proxy = (HibernateProxy) dirty;
+            LazyInitializer lazyInitializer = 
proxy.getHibernateLazyInitializer();
+            if (lazyInitializer.isUninitialized()) {
+                return true;
+            } else {
+                dirty = lazyInitializer.getImplementation();
+                doClean(dirty, processed);
+            }
+            return true;
+        }
+        return false;
+    }
+
+    private static Object doHibernateClean(Object dirty, Map<Object, Object> 
processed) {
+        if (dirty instanceof PersistentList) {
+            PersistentList dirtyList = (PersistentList) dirty;
+            List<Object> cleanList = new ArrayList<Object>();
+            processed.put(dirtyList, cleanList);
+            if (dirtyList.wasInitialized()) {
+                for (Object value : dirtyList) {
+                    cleanList.add(doClean(value, processed));
+                }
+            }
+            return cleanList;
+        }
+
+        if (dirty instanceof PersistentBag) {
+            PersistentBag dirtyList = (PersistentBag) dirty;
+            List<Object> cleanList = new ArrayList<Object>();
+            processed.put(dirtyList, cleanList);
+            if (dirtyList.wasInitialized()) {
+                for (Object value : dirtyList) {
+                    cleanList.add(doClean(value, processed));
+                }
+            }
+            return cleanList;
+        }
+
+        if (dirty instanceof PersistentSortedSet) {
+            PersistentSortedSet dirtySet = (PersistentSortedSet) dirty;
+            Set<Object> cleanSet = new TreeSet<Object>();
+            processed.put(dirtySet, cleanSet);
+            if (dirtySet.wasInitialized()) {
+                for (Object value : dirtySet) {
+                    cleanSet.add(doClean(value, processed));
+                }
+            }
+            return cleanSet;
+        }
+
+        if (dirty instanceof PersistentSet) {
+            PersistentSet dirtySet = (PersistentSet) dirty;
+            Set<Object> cleanSet = new HashSet<Object>();
+            processed.put(dirtySet, cleanSet);
+            if (dirtySet.wasInitialized()) {
+                for (Object value : dirtySet) {
+                    cleanSet.add(doClean(value, processed));
+                }
+            }
+            return cleanSet;
+        }
+
+        if (dirty instanceof PersistentMap) {
+            PersistentMap dirtyMap = (PersistentMap) dirty;
+            Map<Object, Object> cleanMap = new LinkedHashMap<Object, Object>();
+            processed.put(dirtyMap, cleanMap);
+            if (dirtyMap.wasInitialized()) {
+                for (Object key : dirtyMap.keySet()) {
+                    Object value = dirtyMap.get(key);
+                    cleanMap.put(doClean(key, processed), doClean(value, 
processed));
+                }
+            }
+            return cleanMap;
+        }
+        return null;
+    }
+
+    private static boolean isPrimitive(Object object) {
+        if (object instanceof String) {
+            return true;
+        }
+
+        if (object instanceof Date) {
+            return true;
+        }
+
+        if (object instanceof Enum) {
+            return true;
+        }
+
+        Class<? extends Object> clazz = object.getClass();
+        if (clazz.isPrimitive()) {
+            return true;
+        }
+
+        return false;
+    }
+
+}
diff --git 
a/frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/server/gwt/hibernate/ReflectionUtils.java
 
b/frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/server/gwt/hibernate/ReflectionUtils.java
new file mode 100644
index 0000000..f887e402
--- /dev/null
+++ 
b/frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/server/gwt/hibernate/ReflectionUtils.java
@@ -0,0 +1,67 @@
+package org.ovirt.engine.ui.frontend.server.gwt.hibernate;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+
+public class ReflectionUtils {
+    public static List<String> getGetterNames(Object object) {
+        List<String> properties = new ArrayList<String>();
+        Class<? extends Object> xClass = object.getClass();
+        for (Method method : xClass.getMethods()) {
+            if (isGetter(method)) {
+                properties.add(method.getName());
+            }
+        }
+        return properties;
+    }
+
+    private static boolean isGetter(Method method) {
+        String name = method.getName();
+        if (!name.startsWith("get")) //$NON-NLS-1$
+            return false;
+        if (name.length() == 3)
+            return false;
+        if (name.equals("getClass")) //$NON-NLS-1$
+            return false;
+        if (void.class.equals(method.getReturnType()))
+            return false;
+        if (method.getParameterTypes().length != 0)
+            return false;
+        return true;
+    }
+
+    @SuppressWarnings("unchecked")
+    public static <T> T get(Object object, String methodName) {
+        try {
+            Class<? extends Object> xClass = object.getClass();
+            Method method = xClass.getMethod(methodName);
+            return (T) method.invoke(object);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public static void setIfPossible(Object object, String getterMethodName, 
Object value) {
+        try {
+            Class<? extends Object> xClass = object.getClass();
+            String methodName = "s" + getterMethodName.substring(1, 
getterMethodName.length()); //$NON-NLS-1$
+            Method method = getMethod(xClass, methodName);
+            if (method == null) {
+                return;
+            }
+            method.invoke(object, value);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private static Method getMethod(Class<?> Clazz, String name) {
+        Method[] methods = Clazz.getMethods();
+        for (Method method : methods) {
+            if (method.getName().equals(name))
+                return method;
+        }
+        return null;
+    }
+}
diff --git 
a/frontend/webadmin/modules/gwt-extension/src/main/java/org/ovirt/engine/ui/uioverrides/org/hibernate/collection/internal/PersistentBag.java
 
b/frontend/webadmin/modules/gwt-extension/src/main/java/org/ovirt/engine/ui/uioverrides/org/hibernate/collection/internal/PersistentBag.java
deleted file mode 100644
index c55c4fb..0000000
--- 
a/frontend/webadmin/modules/gwt-extension/src/main/java/org/ovirt/engine/ui/uioverrides/org/hibernate/collection/internal/PersistentBag.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package org.hibernate.collection.internal;
-
-import java.util.ArrayList;
-
-/**
- * This is how we tell GWT to serialize the hibernate class PersistentBag.
- * We don't need the real implementation in the UI, and since we only use
- * the List interface, the transformation to ArrayList is valid.
- */
-public class PersistentBag extends ArrayList {
-
-}


-- 
To view, visit https://gerrit.ovirt.org/41810
To unsubscribe, visit https://gerrit.ovirt.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I4eac0864e844ad8e1885134df69f976c784b3960
Gerrit-PatchSet: 1
Gerrit-Project: ovirt-engine
Gerrit-Branch: master
Gerrit-Owner: Alexander Wels <aw...@redhat.com>
_______________________________________________
Engine-patches mailing list
Engine-patches@ovirt.org
http://lists.ovirt.org/mailman/listinfo/engine-patches

Reply via email to