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