modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/util/SerialUtility.java | 2 modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/startup/ExternalizableStrategyCommandListener.java | 2 modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/agentclient/impl/AgentClientImpl.java | 2 modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/bundle/BundleManagerBean.java | 4 modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/bundle/BundleServerServiceImpl.java | 4 modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/remote/RemoteSafeInvocationHandler.java | 2 modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/remote/RemoteWsInvocationHandler.java | 2 modules/enterprise/server/safe-invoker/src/main/java/org/rhq/enterprise/server/safeinvoker/EJB3SafeEndpointInvoker.java | 60 + modules/enterprise/server/safe-invoker/src/main/java/org/rhq/enterprise/server/safeinvoker/EJB3SafeEndpointInvokerDeploymentAspect.java | 60 + modules/enterprise/server/safe-invoker/src/main/java/org/rhq/enterprise/server/safeinvoker/HibernateDetachUtility.java | 359 ++++++++++ modules/enterprise/server/safe-invoker/src/main/java/org/rhq/enterprise/server/util/EJB3SafeEndpointInvoker.java | 58 - modules/enterprise/server/safe-invoker/src/main/java/org/rhq/enterprise/server/util/EJB3SafeEndpointInvokerDeploymentAspect.java | 59 - modules/enterprise/server/safe-invoker/src/main/java/org/rhq/enterprise/server/util/HibernateDetachUtility.java | 359 ---------- 13 files changed, 488 insertions(+), 485 deletions(-)
New commits: commit 1640208cb264519a0c1e6a5dae296a97a23ae6d3 Merge: d820e17... 0018dbe... Author: Simeon Pinder spinder@redhat.com Date: Mon Jan 24 19:01:46 2011 -0500
Merge branch 'release-3.0.0-test-build' of ssh://spinder@git.fedorahosted.org/git/rhq/rhq into release-3.0.0-test-build
commit d820e17ac7723444da38b074020b6f0eed8d8f3c Author: Simeon Pinder spinder@redhat.com Date: Mon Jan 24 18:14:03 2011 -0500
BZ:672174 moving safeinvoker pkgs out of org.rhq.enterprise.server to avoid signing conflicts.
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/util/SerialUtility.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/util/SerialUtility.java index 7433805..cbbb312 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/util/SerialUtility.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/util/SerialUtility.java @@ -18,7 +18,7 @@ */ package org.rhq.enterprise.gui.coregui.server.util;
-import org.rhq.enterprise.server.util.HibernateDetachUtility; +import org.rhq.enterprise.server.safeinvoker.HibernateDetachUtility;
import java.io.ByteArrayOutputStream; import java.io.IOException; diff --git a/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/startup/ExternalizableStrategyCommandListener.java b/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/startup/ExternalizableStrategyCommandListener.java index a845c39..7ca48b2 100644 --- a/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/startup/ExternalizableStrategyCommandListener.java +++ b/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/startup/ExternalizableStrategyCommandListener.java @@ -23,7 +23,7 @@ import org.rhq.enterprise.communications.command.Command; import org.rhq.enterprise.communications.command.CommandResponse; import org.rhq.enterprise.communications.command.client.CommandPreprocessor; import org.rhq.enterprise.communications.command.server.CommandListener; -import org.rhq.enterprise.server.util.HibernateDetachUtility; +import org.rhq.enterprise.server.safeinvoker.HibernateDetachUtility;
/** * This is a listener for commands coming into the {@link ServiceContainer}'s {@link CommandPreprocessor} and will diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/agentclient/impl/AgentClientImpl.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/agentclient/impl/AgentClientImpl.java index fb46b77..43c2b60 100644 --- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/agentclient/impl/AgentClientImpl.java +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/agentclient/impl/AgentClientImpl.java @@ -35,7 +35,7 @@ import org.rhq.enterprise.communications.command.client.ClientCommandSender; import org.rhq.enterprise.communications.command.client.ClientRemotePojoFactory; import org.rhq.enterprise.communications.command.client.SendCallback; import org.rhq.enterprise.server.agentclient.AgentClient; -import org.rhq.enterprise.server.util.HibernateDetachUtility; +import org.rhq.enterprise.server.safeinvoker.HibernateDetachUtility;
/** * Provides the mechanism by which you obtain remote interface proxies to a particular agent. Using those remote diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/bundle/BundleManagerBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/bundle/BundleManagerBean.java index e6fc90c..1b98081 100644 --- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/bundle/BundleManagerBean.java +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/bundle/BundleManagerBean.java @@ -96,10 +96,10 @@ import org.rhq.enterprise.server.core.AgentManagerLocal; import org.rhq.enterprise.server.plugin.pc.bundle.BundleServerPluginManager; import org.rhq.enterprise.server.resource.ResourceTypeManagerLocal; import org.rhq.enterprise.server.resource.group.ResourceGroupManagerLocal; +import org.rhq.enterprise.server.safeinvoker.HibernateDetachUtility; +import org.rhq.enterprise.server.safeinvoker.HibernateDetachUtility.SerializationType; import org.rhq.enterprise.server.util.CriteriaQueryGenerator; import org.rhq.enterprise.server.util.CriteriaQueryRunner; -import org.rhq.enterprise.server.util.HibernateDetachUtility; -import org.rhq.enterprise.server.util.HibernateDetachUtility.SerializationType;
/** * Manages the creation and usage of bundles. diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/bundle/BundleServerServiceImpl.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/bundle/BundleServerServiceImpl.java index 1fc6e1a..65a1209 100644 --- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/bundle/BundleServerServiceImpl.java +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/bundle/BundleServerServiceImpl.java @@ -36,9 +36,9 @@ import org.rhq.core.domain.criteria.PackageVersionCriteria; import org.rhq.core.util.exception.WrappedRemotingException; import org.rhq.enterprise.server.content.ContentManagerLocal; import org.rhq.enterprise.server.content.ContentSourceManagerLocal; -import org.rhq.enterprise.server.util.HibernateDetachUtility; +import org.rhq.enterprise.server.safeinvoker.HibernateDetachUtility; +import org.rhq.enterprise.server.safeinvoker.HibernateDetachUtility.SerializationType; import org.rhq.enterprise.server.util.LookupUtil; -import org.rhq.enterprise.server.util.HibernateDetachUtility.SerializationType;
/** * Server-side implementation of the <code>BundleServerService</code>. This implmentation simply forwards diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/remote/RemoteSafeInvocationHandler.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/remote/RemoteSafeInvocationHandler.java index 70ab414..d11cc03 100644 --- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/remote/RemoteSafeInvocationHandler.java +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/remote/RemoteSafeInvocationHandler.java @@ -37,7 +37,7 @@ import org.jboss.remoting.invocation.NameBasedInvocation;
import org.rhq.core.server.ExternalizableStrategy; import org.rhq.core.util.exception.WrappedRemotingException; -import org.rhq.enterprise.server.util.HibernateDetachUtility; +import org.rhq.enterprise.server.safeinvoker.HibernateDetachUtility;
/** * Handle remote invocations. Note that we perform only invocations defined in the remote interfaces. diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/remote/RemoteWsInvocationHandler.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/remote/RemoteWsInvocationHandler.java index c681bbc..22cbddb 100644 --- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/remote/RemoteWsInvocationHandler.java +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/remote/RemoteWsInvocationHandler.java @@ -28,7 +28,7 @@ import org.jboss.remoting.callback.InvokerCallbackHandler; import org.jboss.remoting.invocation.NameBasedInvocation;
import org.rhq.core.server.ExternalizableStrategy; -import org.rhq.enterprise.server.util.HibernateDetachUtility; +import org.rhq.enterprise.server.safeinvoker.HibernateDetachUtility;
public class RemoteWsInvocationHandler implements ServerInvocationHandler {
diff --git a/modules/enterprise/server/safe-invoker/src/main/java/org/rhq/enterprise/server/safeinvoker/EJB3SafeEndpointInvoker.java b/modules/enterprise/server/safe-invoker/src/main/java/org/rhq/enterprise/server/safeinvoker/EJB3SafeEndpointInvoker.java new file mode 100644 index 0000000..fb65713 --- /dev/null +++ b/modules/enterprise/server/safe-invoker/src/main/java/org/rhq/enterprise/server/safeinvoker/EJB3SafeEndpointInvoker.java @@ -0,0 +1,60 @@ +/* + * RHQ Management Platform + * Copyright (C) 2005-2008 Red Hat, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +package org.rhq.enterprise.server.safeinvoker; + +import java.lang.reflect.Method; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.jboss.ws.core.EndpointInvocation; +import org.jboss.ws.core.server.ServiceEndpointInvoker; +import org.jboss.wsf.spi.invocation.InvocationContext; + +import org.rhq.enterprise.server.safeinvoker.HibernateDetachUtility.SerializationType; + +/** + * This invoker will take an uninitialized relationships or references from EJB3 pojo's and null them out so that we can + * pass them as normal objects to the webservice binding layer. (Avoiding LazyInitializationExceptions) + * + * @author Greg Hinkle + */ +public class EJB3SafeEndpointInvoker extends ServiceEndpointInvoker { + private static final Log LOG = LogFactory.getLog(EJB3SafeEndpointInvoker.class); + + @Override + public void invoke(InvocationContext invocationContext) throws Exception { + super.invoke(invocationContext); + EndpointInvocation inv = invocationContext.getAttachment(EndpointInvocation.class); + Object value = inv.getReturnValue(); + if (value != null) { + try { + Method m = value.getClass().getMethod("getReturn"); + if (m != null) { + HibernateDetachUtility.nullOutUninitializedFields(value, + HibernateDetachUtility.SerializationType.JAXB); + } + + inv.setReturnValue(value); + } catch (NoSuchMethodException nsme) { + // Expected for void return types + } + } + } +} \ No newline at end of file diff --git a/modules/enterprise/server/safe-invoker/src/main/java/org/rhq/enterprise/server/safeinvoker/EJB3SafeEndpointInvokerDeploymentAspect.java b/modules/enterprise/server/safe-invoker/src/main/java/org/rhq/enterprise/server/safeinvoker/EJB3SafeEndpointInvokerDeploymentAspect.java new file mode 100644 index 0000000..709dc86 --- /dev/null +++ b/modules/enterprise/server/safe-invoker/src/main/java/org/rhq/enterprise/server/safeinvoker/EJB3SafeEndpointInvokerDeploymentAspect.java @@ -0,0 +1,60 @@ +/* + * RHQ Management Platform + * Copyright (C) 2005-2008 Red Hat, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +package org.rhq.enterprise.server.safeinvoker; + +import java.util.Iterator; + +import org.jboss.ws.core.server.ServiceEndpointInvoker; +import org.jboss.ws.core.server.ServiceEndpointInvokerEJB21; +import org.jboss.wsf.spi.deployment.Deployment; +import org.jboss.wsf.spi.deployment.DeploymentAspect; +import org.jboss.wsf.spi.deployment.Endpoint; + + +/** + * This class installs the EJB3SafeEndpointInvoker into the deployment aspect for the endpoint. + * + * @author Greg Hinkle + */ +public class EJB3SafeEndpointInvokerDeploymentAspect extends DeploymentAspect { + @Override + public void start(Deployment dep) { + Iterator i$ = dep.getService().getEndpoints().iterator(); + do { + if (!i$.hasNext()) { + break; + } + + Endpoint ep = (Endpoint) i$.next(); + ServiceEndpointInvoker epInvoker = ep.getAttachment(ServiceEndpointInvoker.class); + if (epInvoker == null) { + org.jboss.wsf.spi.deployment.Deployment.DeploymentType depType = ep.getService().getDeployment() + .getType(); + if (depType == org.jboss.wsf.spi.deployment.Deployment.DeploymentType.JAXRPC_EJB21) { + epInvoker = new ServiceEndpointInvokerEJB21(); + } else { + epInvoker = new EJB3SafeEndpointInvoker(); + } + + ep.addAttachment(org.jboss.ws.core.server.ServiceEndpointInvoker.class, epInvoker); + epInvoker.init(ep); + } + } while (true); + } +} \ No newline at end of file diff --git a/modules/enterprise/server/safe-invoker/src/main/java/org/rhq/enterprise/server/safeinvoker/HibernateDetachUtility.java b/modules/enterprise/server/safe-invoker/src/main/java/org/rhq/enterprise/server/safeinvoker/HibernateDetachUtility.java new file mode 100644 index 0000000..803f9ce --- /dev/null +++ b/modules/enterprise/server/safe-invoker/src/main/java/org/rhq/enterprise/server/safeinvoker/HibernateDetachUtility.java @@ -0,0 +1,359 @@ +/* + * RHQ Management Platform + * Copyright (C) 2005-2008 Red Hat, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +package org.rhq.enterprise.server.safeinvoker; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.hibernate.Hibernate; +import org.hibernate.proxy.HibernateProxy; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlTransient; + +import java.beans.BeanInfo; +import java.beans.Introspector; +import java.beans.PropertyDescriptor; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.ListIterator; +import java.util.Map; +import java.util.Set; + +/** + * @author Greg Hinkle + */ +public class HibernateDetachUtility { + + private static final Log LOG = LogFactory.getLog(HibernateDetachUtility.class); + + public static enum SerializationType { + SERIALIZATION, JAXB + } + + public static void nullOutUninitializedFields(Object value, SerializationType serializationType) throws Exception { + long start = System.currentTimeMillis(); + Set<Integer> checkedObjs = new HashSet<Integer>(); + nullOutUninitializedFields(value, checkedObjs, 0, serializationType); + long duration = System.currentTimeMillis() - start; + if (duration > 1000) { + LOG.info("Detached [" + checkedObjs.size() + "] objects in [" + duration + "]ms"); + } else { + LOG.debug("Detached [" + checkedObjs.size() + "] objects in [" + duration + "]ms"); + } + } + + private static void nullOutUninitializedFields(Object value, Set<Integer> nulledObjects, int depth, + SerializationType serializationType) throws Exception { + if (depth > 50) { + LOG.warn("Getting different object hierarchies back from calls: " + value.getClass().getName()); + return; + } + + if ((value == null) || nulledObjects.contains(System.identityHashCode(value))) { + return; + } + + nulledObjects.add(System.identityHashCode(value)); + + if (value instanceof Object[]) { + Object[] objArray = (Object[]) value; + for (int i = 0; i < objArray.length; i++) { + nullOutUninitializedFields(objArray[i], nulledObjects, depth + 1, serializationType); + } + + } else if (value instanceof List) { + // Null out any entries in initialized collections + ListIterator i = ((List)value).listIterator(); + while (i.hasNext()) { + Object val = i.next(); + Object replace = replaceObject(val); + if (replace != null) { + val = replace; + i.set(replace); + } + nullOutUninitializedFields(val, nulledObjects, depth + 1, serializationType); + } + + } else if (value instanceof Collection) { + Collection collection = (Collection) value; + Collection itemsToBeReplaced = new ArrayList(); + Collection replacementItems = new ArrayList(); + for (Object item : collection) { + Object replacementItem = replaceObject(item); + if (replacementItem != null) { + itemsToBeReplaced.add(item); + replacementItems.add(replacementItem); + item = replacementItem; + } + nullOutUninitializedFields(item, nulledObjects, depth + 1, serializationType); + } + collection.removeAll(itemsToBeReplaced); + collection.addAll(replacementItems); + } else if (value instanceof Map) { + for (Object key : ((Map) value).keySet()) { + nullOutUninitializedFields(((Map) value).get(key), nulledObjects, depth + 1, serializationType); + nullOutUninitializedFields(key, nulledObjects, depth + 1, serializationType); + } + } else if (value instanceof Enum) { + // don't need to detach enums, treat them as special objects + return; + } + + + if (serializationType == SerializationType.JAXB) { + XmlAccessorType at = value.getClass().getAnnotation(XmlAccessorType.class); + if (at != null && at.value() == XmlAccessType.FIELD) { + //System.out.println("----------XML--------- field access"); + nullOutFieldsByFieldAccess(value, nulledObjects, depth, serializationType); + } else { + //System.out.println("----------XML--------- accessor access"); + nullOutFieldsByAccessors(value, nulledObjects, depth, serializationType); + } + } else if (serializationType == SerializationType.SERIALIZATION) { + // System.out.println("-----------JRMP-------- field access"); + nullOutFieldsByFieldAccess(value, nulledObjects, depth, serializationType); + } + + } + + private static void nullOutFieldsByFieldAccess(Object object, Set<Integer> nulledObjects, int depth, + SerializationType serializationType) throws Exception { + + + Class tmpClass = object.getClass(); + List<Field> fieldsToClean = new ArrayList<Field>(); + while (tmpClass != null && tmpClass != Object.class) { + Collections.addAll(fieldsToClean, tmpClass.getDeclaredFields()); + tmpClass = tmpClass.getSuperclass(); + } + + nullOutFieldsByFieldAccess(object, fieldsToClean, nulledObjects, depth, serializationType); + } + + + @SuppressWarnings("unchecked") + private static void nullOutFieldsByFieldAccess(Object object, List<Field> classFields, Set<Integer> nulledObjects, int depth, + SerializationType serializationType) throws Exception { + + boolean accessModifierFlag = false; + for (Field field : classFields) { + accessModifierFlag = false; + if (!field.isAccessible()) { + field.setAccessible(true); + accessModifierFlag = true; + } + + Object fieldValue = field.get(object); + + if (fieldValue instanceof HibernateProxy) { + + Object replacement = null; + if (fieldValue.getClass().getName().contains("javassist")) { + + Class assistClass = fieldValue.getClass(); + try { + Method m = assistClass.getMethod("writeReplace"); + replacement = m.invoke(fieldValue); + + String className = fieldValue.getClass().getName(); + className = className.substring(0, className.indexOf("_$$_")); + if (!replacement.getClass().getName().contains("hibernate")) { + nullOutUninitializedFields(replacement, nulledObjects, depth + 1, serializationType); + + field.set(object, replacement); + } else { + replacement = null; + } + } catch (Exception e) { + System.out.println("Unable to write replace object " + fieldValue.getClass()); + } + } + + if (replacement == null) { + + String className = ((HibernateProxy) fieldValue).getHibernateLazyInitializer().getEntityName(); + Class clazz = Class.forName(className); + Class[] constArgs = {Integer.class}; + Constructor construct = null; + + try { + construct = clazz.getConstructor(constArgs); + replacement = construct.newInstance((Integer) ((HibernateProxy) fieldValue).getHibernateLazyInitializer().getIdentifier()); + field.set(object, replacement); + } catch (NoSuchMethodException nsme) { + + try { + Field idField = clazz.getDeclaredField("id"); + Constructor ct = clazz.getDeclaredConstructor(); + ct.setAccessible(true); + replacement = ct.newInstance(); + if (!idField.isAccessible()) { + idField.setAccessible(true); + } + idField.set(replacement, (Integer) ((HibernateProxy) fieldValue).getHibernateLazyInitializer().getIdentifier()); + } catch (Exception e) { + e.printStackTrace(); + System.out.println("No id constructor and unable to set field id for base bean " + className); + } + + field.set(object, replacement); + } + } + + + } else { + if (fieldValue instanceof org.hibernate.collection.PersistentCollection) { + // Replace hibernate specific collection types + + if (!((org.hibernate.collection.PersistentCollection) fieldValue).wasInitialized()) { + field.set(object, null); + } else { + + Object replacement = null; + if (fieldValue instanceof Map) { + replacement = new HashMap((Map) fieldValue); + } else if (fieldValue instanceof List) { + replacement = new ArrayList((List) fieldValue); + } else if (fieldValue instanceof Set) { + replacement = new HashSet((Set) fieldValue); + } else if (fieldValue instanceof Collection) { + replacement = new ArrayList((Collection) fieldValue); + } + setField(object, field.getName(), replacement); + + nullOutUninitializedFields(replacement, nulledObjects, depth + 1, serializationType); + } + + } else { + if (fieldValue != null && + (fieldValue.getClass().getName().contains("org.rhq") || + fieldValue instanceof Collection || + fieldValue instanceof Object[] || + fieldValue instanceof Map)) + nullOutUninitializedFields((fieldValue), nulledObjects, depth + 1, serializationType); + } + } + if (accessModifierFlag) { + field.setAccessible(false); + } + } + + } + + + private static Object replaceObject(Object object) { + Object replacement = null; + + if (object instanceof HibernateProxy) { + if (object.getClass().getName().contains("javassist")) { + Class assistClass = object.getClass(); + try { + Method m = assistClass.getMethod("writeReplace"); + replacement = m.invoke(object); + + String className = object.getClass().getName(); + } catch (Exception e) { + System.out.println("Unable to write replace object " + object.getClass()); + } + } + } + return replacement; + } + + + private static void nullOutFieldsByAccessors(Object value, Set<Integer> nulledObjects, int depth, + SerializationType serializationType) throws Exception { + // Null out any collections that aren't loaded + BeanInfo bi = Introspector.getBeanInfo(value.getClass(), Object.class); + + PropertyDescriptor[] pds = bi.getPropertyDescriptors(); + for (PropertyDescriptor pd : pds) { + Object propertyValue = null; + try { + propertyValue = pd.getReadMethod().invoke(value); + } catch (Throwable lie) { + if (LOG.isDebugEnabled()) { + LOG.debug("Couldn't load: " + pd.getName() + " off of " + value.getClass().getSimpleName(), lie); + } + } + + if (!Hibernate.isInitialized(propertyValue)) { + try { + if (LOG.isDebugEnabled()) { + LOG.debug("Nulling out: " + pd.getName() + " off of " + value.getClass().getSimpleName()); + } + + Method writeMethod = pd.getWriteMethod(); + if ((writeMethod != null) && (writeMethod.getAnnotation(XmlTransient.class) == null)) { + pd.getWriteMethod().invoke(value, new Object[]{null}); + } else { + nullOutField(value, pd.getName()); + } + } catch (Exception lie) { + LOG.debug("Couldn't null out: " + pd.getName() + " off of " + value.getClass().getSimpleName() + + " trying field access", lie); + nullOutField(value, pd.getName()); + } + } else { + if ((propertyValue instanceof Collection) + || ((propertyValue != null) && propertyValue.getClass().getName().startsWith("org.rhq.core.domain"))) { + nullOutUninitializedFields(propertyValue, nulledObjects, depth + 1, serializationType); + } + } + } + } + + private static void setField(Object object, String fieldName, Object newValue) { + try { + Field f = object.getClass().getDeclaredField(fieldName); + if (f != null) { + // try to set the field this way + f.setAccessible(true); + f.set(object, newValue); + } + } catch (NoSuchFieldException e) { + // ignore this + } catch (IllegalAccessException e) { + // ignore this + } + } + + private static void nullOutField(Object value, String fieldName) { + try { + Field f = value.getClass().getDeclaredField(fieldName); + if (f != null) { + // try to set the field this way + f.setAccessible(true); + f.set(value, null); + } + } catch (NoSuchFieldException e) { + // ignore this + } catch (IllegalAccessException e) { + // ignore this + } + } +} \ No newline at end of file diff --git a/modules/enterprise/server/safe-invoker/src/main/java/org/rhq/enterprise/server/util/EJB3SafeEndpointInvoker.java b/modules/enterprise/server/safe-invoker/src/main/java/org/rhq/enterprise/server/util/EJB3SafeEndpointInvoker.java deleted file mode 100644 index f605df1..0000000 --- a/modules/enterprise/server/safe-invoker/src/main/java/org/rhq/enterprise/server/util/EJB3SafeEndpointInvoker.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * RHQ Management Platform - * Copyright (C) 2005-2008 Red Hat, Inc. - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ -package org.rhq.enterprise.server.util; - -import java.lang.reflect.Method; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.jboss.ws.core.EndpointInvocation; -import org.jboss.ws.core.server.ServiceEndpointInvoker; -import org.jboss.wsf.spi.invocation.InvocationContext; - -/** - * This invoker will take an uninitialized relationships or references from EJB3 pojo's and null them out so that we can - * pass them as normal objects to the webservice binding layer. (Avoiding LazyInitializationExceptions) - * - * @author Greg Hinkle - */ -public class EJB3SafeEndpointInvoker extends ServiceEndpointInvoker { - private static final Log LOG = LogFactory.getLog(EJB3SafeEndpointInvoker.class); - - @Override - public void invoke(InvocationContext invocationContext) throws Exception { - super.invoke(invocationContext); - EndpointInvocation inv = invocationContext.getAttachment(EndpointInvocation.class); - Object value = inv.getReturnValue(); - if (value != null) { - try { - Method m = value.getClass().getMethod("getReturn"); - if (m != null) { - HibernateDetachUtility.nullOutUninitializedFields(value, - HibernateDetachUtility.SerializationType.JAXB); - } - - inv.setReturnValue(value); - } catch (NoSuchMethodException nsme) { - // Expected for void return types - } - } - } -} \ No newline at end of file diff --git a/modules/enterprise/server/safe-invoker/src/main/java/org/rhq/enterprise/server/util/EJB3SafeEndpointInvokerDeploymentAspect.java b/modules/enterprise/server/safe-invoker/src/main/java/org/rhq/enterprise/server/util/EJB3SafeEndpointInvokerDeploymentAspect.java deleted file mode 100644 index 9d90417..0000000 --- a/modules/enterprise/server/safe-invoker/src/main/java/org/rhq/enterprise/server/util/EJB3SafeEndpointInvokerDeploymentAspect.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * RHQ Management Platform - * Copyright (C) 2005-2008 Red Hat, Inc. - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ -package org.rhq.enterprise.server.util; - -import java.util.Iterator; - -import org.jboss.ws.core.server.ServiceEndpointInvoker; -import org.jboss.ws.core.server.ServiceEndpointInvokerEJB21; -import org.jboss.wsf.spi.deployment.Deployment; -import org.jboss.wsf.spi.deployment.DeploymentAspect; -import org.jboss.wsf.spi.deployment.Endpoint; - -/** - * This class installs the EJB3SafeEndpointInvoker into the deployment aspect for the endpoint. - * - * @author Greg Hinkle - */ -public class EJB3SafeEndpointInvokerDeploymentAspect extends DeploymentAspect { - @Override - public void start(Deployment dep) { - Iterator i$ = dep.getService().getEndpoints().iterator(); - do { - if (!i$.hasNext()) { - break; - } - - Endpoint ep = (Endpoint) i$.next(); - ServiceEndpointInvoker epInvoker = ep.getAttachment(ServiceEndpointInvoker.class); - if (epInvoker == null) { - org.jboss.wsf.spi.deployment.Deployment.DeploymentType depType = ep.getService().getDeployment() - .getType(); - if (depType == org.jboss.wsf.spi.deployment.Deployment.DeploymentType.JAXRPC_EJB21) { - epInvoker = new ServiceEndpointInvokerEJB21(); - } else { - epInvoker = new EJB3SafeEndpointInvoker(); - } - - ep.addAttachment(org.jboss.ws.core.server.ServiceEndpointInvoker.class, epInvoker); - epInvoker.init(ep); - } - } while (true); - } -} \ No newline at end of file diff --git a/modules/enterprise/server/safe-invoker/src/main/java/org/rhq/enterprise/server/util/HibernateDetachUtility.java b/modules/enterprise/server/safe-invoker/src/main/java/org/rhq/enterprise/server/util/HibernateDetachUtility.java deleted file mode 100644 index e56f076..0000000 --- a/modules/enterprise/server/safe-invoker/src/main/java/org/rhq/enterprise/server/util/HibernateDetachUtility.java +++ /dev/null @@ -1,359 +0,0 @@ -/* - * RHQ Management Platform - * Copyright (C) 2005-2008 Red Hat, Inc. - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ -package org.rhq.enterprise.server.util; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.hibernate.Hibernate; -import org.hibernate.proxy.HibernateProxy; - -import javax.xml.bind.annotation.XmlAccessType; -import javax.xml.bind.annotation.XmlAccessorType; -import javax.xml.bind.annotation.XmlTransient; - -import java.beans.BeanInfo; -import java.beans.Introspector; -import java.beans.PropertyDescriptor; -import java.lang.reflect.Constructor; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.ListIterator; -import java.util.Map; -import java.util.Set; - -/** - * @author Greg Hinkle - */ -public class HibernateDetachUtility { - - private static final Log LOG = LogFactory.getLog(HibernateDetachUtility.class); - - public static enum SerializationType { - SERIALIZATION, JAXB - } - - public static void nullOutUninitializedFields(Object value, SerializationType serializationType) throws Exception { - long start = System.currentTimeMillis(); - Set<Integer> checkedObjs = new HashSet<Integer>(); - nullOutUninitializedFields(value, checkedObjs, 0, serializationType); - long duration = System.currentTimeMillis() - start; - if (duration > 1000) { - LOG.info("Detached [" + checkedObjs.size() + "] objects in [" + duration + "]ms"); - } else { - LOG.debug("Detached [" + checkedObjs.size() + "] objects in [" + duration + "]ms"); - } - } - - private static void nullOutUninitializedFields(Object value, Set<Integer> nulledObjects, int depth, - SerializationType serializationType) throws Exception { - if (depth > 50) { - LOG.warn("Getting different object hierarchies back from calls: " + value.getClass().getName()); - return; - } - - if ((value == null) || nulledObjects.contains(System.identityHashCode(value))) { - return; - } - - nulledObjects.add(System.identityHashCode(value)); - - if (value instanceof Object[]) { - Object[] objArray = (Object[]) value; - for (int i = 0; i < objArray.length; i++) { - nullOutUninitializedFields(objArray[i], nulledObjects, depth + 1, serializationType); - } - - } else if (value instanceof List) { - // Null out any entries in initialized collections - ListIterator i = ((List)value).listIterator(); - while (i.hasNext()) { - Object val = i.next(); - Object replace = replaceObject(val); - if (replace != null) { - val = replace; - i.set(replace); - } - nullOutUninitializedFields(val, nulledObjects, depth + 1, serializationType); - } - - } else if (value instanceof Collection) { - Collection collection = (Collection) value; - Collection itemsToBeReplaced = new ArrayList(); - Collection replacementItems = new ArrayList(); - for (Object item : collection) { - Object replacementItem = replaceObject(item); - if (replacementItem != null) { - itemsToBeReplaced.add(item); - replacementItems.add(replacementItem); - item = replacementItem; - } - nullOutUninitializedFields(item, nulledObjects, depth + 1, serializationType); - } - collection.removeAll(itemsToBeReplaced); - collection.addAll(replacementItems); - } else if (value instanceof Map) { - for (Object key : ((Map) value).keySet()) { - nullOutUninitializedFields(((Map) value).get(key), nulledObjects, depth + 1, serializationType); - nullOutUninitializedFields(key, nulledObjects, depth + 1, serializationType); - } - } else if (value instanceof Enum) { - // don't need to detach enums, treat them as special objects - return; - } - - - if (serializationType == SerializationType.JAXB) { - XmlAccessorType at = value.getClass().getAnnotation(XmlAccessorType.class); - if (at != null && at.value() == XmlAccessType.FIELD) { - //System.out.println("----------XML--------- field access"); - nullOutFieldsByFieldAccess(value, nulledObjects, depth, serializationType); - } else { - //System.out.println("----------XML--------- accessor access"); - nullOutFieldsByAccessors(value, nulledObjects, depth, serializationType); - } - } else if (serializationType == SerializationType.SERIALIZATION) { - // System.out.println("-----------JRMP-------- field access"); - nullOutFieldsByFieldAccess(value, nulledObjects, depth, serializationType); - } - - } - - private static void nullOutFieldsByFieldAccess(Object object, Set<Integer> nulledObjects, int depth, - SerializationType serializationType) throws Exception { - - - Class tmpClass = object.getClass(); - List<Field> fieldsToClean = new ArrayList<Field>(); - while (tmpClass != null && tmpClass != Object.class) { - Collections.addAll(fieldsToClean, tmpClass.getDeclaredFields()); - tmpClass = tmpClass.getSuperclass(); - } - - nullOutFieldsByFieldAccess(object, fieldsToClean, nulledObjects, depth, serializationType); - } - - - @SuppressWarnings("unchecked") - private static void nullOutFieldsByFieldAccess(Object object, List<Field> classFields, Set<Integer> nulledObjects, int depth, - SerializationType serializationType) throws Exception { - - boolean accessModifierFlag = false; - for (Field field : classFields) { - accessModifierFlag = false; - if (!field.isAccessible()) { - field.setAccessible(true); - accessModifierFlag = true; - } - - Object fieldValue = field.get(object); - - if (fieldValue instanceof HibernateProxy) { - - Object replacement = null; - if (fieldValue.getClass().getName().contains("javassist")) { - - Class assistClass = fieldValue.getClass(); - try { - Method m = assistClass.getMethod("writeReplace"); - replacement = m.invoke(fieldValue); - - String className = fieldValue.getClass().getName(); - className = className.substring(0, className.indexOf("_$$_")); - if (!replacement.getClass().getName().contains("hibernate")) { - nullOutUninitializedFields(replacement, nulledObjects, depth + 1, serializationType); - - field.set(object, replacement); - } else { - replacement = null; - } - } catch (Exception e) { - System.out.println("Unable to write replace object " + fieldValue.getClass()); - } - } - - if (replacement == null) { - - String className = ((HibernateProxy) fieldValue).getHibernateLazyInitializer().getEntityName(); - Class clazz = Class.forName(className); - Class[] constArgs = {Integer.class}; - Constructor construct = null; - - try { - construct = clazz.getConstructor(constArgs); - replacement = construct.newInstance((Integer) ((HibernateProxy) fieldValue).getHibernateLazyInitializer().getIdentifier()); - field.set(object, replacement); - } catch (NoSuchMethodException nsme) { - - try { - Field idField = clazz.getDeclaredField("id"); - Constructor ct = clazz.getDeclaredConstructor(); - ct.setAccessible(true); - replacement = ct.newInstance(); - if (!idField.isAccessible()) { - idField.setAccessible(true); - } - idField.set(replacement, (Integer) ((HibernateProxy) fieldValue).getHibernateLazyInitializer().getIdentifier()); - } catch (Exception e) { - e.printStackTrace(); - System.out.println("No id constructor and unable to set field id for base bean " + className); - } - - field.set(object, replacement); - } - } - - - } else { - if (fieldValue instanceof org.hibernate.collection.PersistentCollection) { - // Replace hibernate specific collection types - - if (!((org.hibernate.collection.PersistentCollection) fieldValue).wasInitialized()) { - field.set(object, null); - } else { - - Object replacement = null; - if (fieldValue instanceof Map) { - replacement = new HashMap((Map) fieldValue); - } else if (fieldValue instanceof List) { - replacement = new ArrayList((List) fieldValue); - } else if (fieldValue instanceof Set) { - replacement = new HashSet((Set) fieldValue); - } else if (fieldValue instanceof Collection) { - replacement = new ArrayList((Collection) fieldValue); - } - setField(object, field.getName(), replacement); - - nullOutUninitializedFields(replacement, nulledObjects, depth + 1, serializationType); - } - - } else { - if (fieldValue != null && - (fieldValue.getClass().getName().contains("org.rhq") || - fieldValue instanceof Collection || - fieldValue instanceof Object[] || - fieldValue instanceof Map)) - nullOutUninitializedFields((fieldValue), nulledObjects, depth + 1, serializationType); - } - } - if (accessModifierFlag) { - field.setAccessible(false); - } - } - - } - - - private static Object replaceObject(Object object) { - Object replacement = null; - - if (object instanceof HibernateProxy) { - if (object.getClass().getName().contains("javassist")) { - Class assistClass = object.getClass(); - try { - Method m = assistClass.getMethod("writeReplace"); - replacement = m.invoke(object); - - String className = object.getClass().getName(); - } catch (Exception e) { - System.out.println("Unable to write replace object " + object.getClass()); - } - } - } - return replacement; - } - - - private static void nullOutFieldsByAccessors(Object value, Set<Integer> nulledObjects, int depth, - SerializationType serializationType) throws Exception { - // Null out any collections that aren't loaded - BeanInfo bi = Introspector.getBeanInfo(value.getClass(), Object.class); - - PropertyDescriptor[] pds = bi.getPropertyDescriptors(); - for (PropertyDescriptor pd : pds) { - Object propertyValue = null; - try { - propertyValue = pd.getReadMethod().invoke(value); - } catch (Throwable lie) { - if (LOG.isDebugEnabled()) { - LOG.debug("Couldn't load: " + pd.getName() + " off of " + value.getClass().getSimpleName(), lie); - } - } - - if (!Hibernate.isInitialized(propertyValue)) { - try { - if (LOG.isDebugEnabled()) { - LOG.debug("Nulling out: " + pd.getName() + " off of " + value.getClass().getSimpleName()); - } - - Method writeMethod = pd.getWriteMethod(); - if ((writeMethod != null) && (writeMethod.getAnnotation(XmlTransient.class) == null)) { - pd.getWriteMethod().invoke(value, new Object[]{null}); - } else { - nullOutField(value, pd.getName()); - } - } catch (Exception lie) { - LOG.debug("Couldn't null out: " + pd.getName() + " off of " + value.getClass().getSimpleName() - + " trying field access", lie); - nullOutField(value, pd.getName()); - } - } else { - if ((propertyValue instanceof Collection) - || ((propertyValue != null) && propertyValue.getClass().getName().startsWith("org.rhq.core.domain"))) { - nullOutUninitializedFields(propertyValue, nulledObjects, depth + 1, serializationType); - } - } - } - } - - private static void setField(Object object, String fieldName, Object newValue) { - try { - Field f = object.getClass().getDeclaredField(fieldName); - if (f != null) { - // try to set the field this way - f.setAccessible(true); - f.set(object, newValue); - } - } catch (NoSuchFieldException e) { - // ignore this - } catch (IllegalAccessException e) { - // ignore this - } - } - - private static void nullOutField(Object value, String fieldName) { - try { - Field f = value.getClass().getDeclaredField(fieldName); - if (f != null) { - // try to set the field this way - f.setAccessible(true); - f.set(value, null); - } - } catch (NoSuchFieldException e) { - // ignore this - } catch (IllegalAccessException e) { - // ignore this - } - } -} \ No newline at end of file
rhq-commits@lists.fedorahosted.org