From 86918ab7f8b3889bd6cf977cd809f30316604dd4 Mon Sep 17 00:00:00 2001
From: felmer <felmer>
Date: Wed, 11 Feb 2009 10:40:52 +0000
Subject: [PATCH] LMS-740 HibernateTransformer moved from 'lims' to 'openbis'

SVN: 9788
---
 openbis/.classpath                            |   1 +
 .../server/util/HibernateTransformer.java     | 188 ++++++++++++++++++
 .../source/java/genericApplicationContext.xml |   6 +
 3 files changed, 195 insertions(+)
 create mode 100644 openbis/source/java/ch/systemsx/cisd/openbis/generic/server/util/HibernateTransformer.java

diff --git a/openbis/.classpath b/openbis/.classpath
index e8ca6ca4ea9..5e72aa968a3 100644
--- a/openbis/.classpath
+++ b/openbis/.classpath
@@ -46,5 +46,6 @@
 	<classpathentry kind="lib" path="/libraries/commons-fileupload/commons-fileupload.jar" sourcepath="/libraries/commons-fileupload/src.zip"/>
 	<classpathentry kind="lib" path="/libraries/lucene-highlighter/lucene-highlighter.jar"/>
 	<classpathentry kind="lib" path="/libraries/beanlib-hibernate/beanlib-hibernate.jar" sourcepath="/libraries/beanlib-hibernate/src.jar"/>
+	<classpathentry kind="lib" path="/libraries/beanlib/beanlib.jar" sourcepath="/libraries/beanlib/src.jar"/>
 	<classpathentry kind="output" path="targets/classes"/>
 </classpath>
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/util/HibernateTransformer.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/util/HibernateTransformer.java
new file mode 100644
index 00000000000..ce8d6339be5
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/util/HibernateTransformer.java
@@ -0,0 +1,188 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * Licensed 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 ch.systemsx.cisd.openbis.generic.server.util;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import net.sf.beanlib.hibernate.HibernateBeanReplicator;
+import net.sf.beanlib.hibernate3.Hibernate3BeanTransformer;
+import net.sf.beanlib.hibernate3.Hibernate3CollectionReplicator;
+import net.sf.beanlib.hibernate3.Hibernate3JavaBeanReplicator;
+import net.sf.beanlib.spi.BeanTransformerSpi;
+import net.sf.beanlib.spi.replicator.BeanReplicatorSpi;
+import net.sf.beanlib.spi.replicator.CollectionReplicatorSpi;
+import net.sf.beanlib.spi.replicator.CollectionReplicatorSpi.Factory;
+
+import org.aopalliance.intercept.MethodInterceptor;
+import org.aopalliance.intercept.MethodInvocation;
+import org.hibernate.Hibernate;
+import org.hibernate.collection.PersistentCollection;
+import org.hibernate.proxy.HibernateProxy;
+
+import ch.systemsx.cisd.common.collections.UnmodifiableCollectionDecorator;
+import ch.systemsx.cisd.common.exceptions.NotImplementedException;
+
+/**
+ * A {@link MethodInterceptor} implementation to get rid of <i>Hibernate</i> proxy classes like
+ * {@link PersistentCollection} or {@link HibernateProxy}.
+ * <p>
+ * Note that this interceptor should only be used on the service layer (when the object is
+ * <i>detached</i> and when database transactions are closed). Otherwise they might trigger <i>SQL</i>
+ * calls.
+ * </p>
+ * 
+ * @author Christian Ribeaud
+ */
+public final class HibernateTransformer implements MethodInterceptor
+{
+
+    private final static ThreadLocal<HibernateBeanReplicator> HIBERNATE_BEAN_REPLICATOR =
+            new ThreadLocal<HibernateBeanReplicator>()
+                {
+
+                    private final HibernateBeanReplicator createHibernateBeanReplicator()
+                    {
+                        final Hibernate3BeanTransformer beanTransformer =
+                                Hibernate3BeanTransformer.newBeanTransformer();
+                        beanTransformer
+                                .initCollectionReplicatable(new CollectionReplicatorSpiFactory());
+                        beanTransformer.initBeanReplicatable(new BeanReplicatorSpiFactory());
+                        return new HibernateBeanReplicator(beanTransformer);
+                    }
+
+                    //
+                    // ThreadLocal
+                    //
+
+                    @Override
+                    protected final HibernateBeanReplicator initialValue()
+                    {
+                        return createHibernateBeanReplicator();
+                    }
+                };
+
+    //
+    // MethodInterceptor
+    //
+
+    public final Object invoke(final MethodInvocation methodInvocation) throws Throwable
+    {
+        final Object proceed = methodInvocation.proceed();
+        if (proceed != null)
+        {
+            return HIBERNATE_BEAN_REPLICATOR.get().copy(proceed);
+        }
+        return null;
+    }
+
+    //
+    // Helper classes
+    //
+
+    private static final class BeanReplicatorSpiFactory implements BeanReplicatorSpi.Factory
+    {
+
+        //
+        // Factory
+        //
+
+        public final BeanReplicatorSpi newBeanReplicatable(final BeanTransformerSpi beanTransformer)
+        {
+            return new NoInitializationHibernate3JavaBeanReplicator(beanTransformer);
+        }
+    }
+
+    private static final class CollectionReplicatorSpiFactory implements Factory
+    {
+
+        //
+        // Factory
+        //
+
+        public final CollectionReplicatorSpi newCollectionReplicatable(
+                final BeanTransformerSpi beanTransformerSpi)
+        {
+            return new NoInitializationHibernate3CollectionReplicator(beanTransformerSpi);
+        }
+    }
+
+    private static final class NoInitializationHibernate3CollectionReplicator extends
+            Hibernate3CollectionReplicator
+    {
+
+        NoInitializationHibernate3CollectionReplicator(final BeanTransformerSpi beanTransformer)
+        {
+            super(beanTransformer);
+        }
+
+        //
+        // Hibernate3CollectionReplicator
+        //
+
+        @SuppressWarnings("unchecked")
+        @Override
+        public final <V, T> T replicateCollection(final Collection<V> from, final Class<T> toClass)
+        {
+            final boolean unmodifiable = (from instanceof UnmodifiableCollectionDecorator);
+            final Collection<V> realFrom =
+                    (unmodifiable) ? ((UnmodifiableCollectionDecorator<V>) from).getDecorated()
+                            : from;
+            if (Hibernate.isInitialized(realFrom) == false)
+            {
+                if (realFrom instanceof Set)
+                {
+                    return (T) new HashSet(0);
+                } else if (realFrom instanceof List)
+                {
+                    return (T) new ArrayList(0);
+                } else
+                {
+                    throw new NotImplementedException();
+                }
+            }
+            return super.replicateCollection(realFrom, toClass);
+        }
+    }
+
+    private static final class NoInitializationHibernate3JavaBeanReplicator extends
+            Hibernate3JavaBeanReplicator
+    {
+
+        NoInitializationHibernate3JavaBeanReplicator(final BeanTransformerSpi beanTransformer)
+        {
+            super(beanTransformer);
+        }
+
+        //
+        // Hibernate3JavaBeanReplicator
+        //
+
+        @Override
+        public final <V, T> T replicateBean(final V from, final Class<T> toClass)
+        {
+            if (Hibernate.isInitialized(from) == false)
+            {
+                return null;
+            }
+            return super.replicateBean(from, toClass);
+        }
+    }
+}
diff --git a/openbis/source/java/genericApplicationContext.xml b/openbis/source/java/genericApplicationContext.xml
index 6b9f9007a52..9eab10df0ec 100644
--- a/openbis/source/java/genericApplicationContext.xml
+++ b/openbis/source/java/genericApplicationContext.xml
@@ -88,6 +88,12 @@
         <constructor-arg ref="common-business-object-factory" />
     </bean>
 
+    <!-- 
+        // Hibernate transformer
+    -->
+
+    <bean id="hibernate-transformer" class="ch.systemsx.cisd.openbis.generic.server.util.HibernateTransformer" />
+    
     <!-- 
         // Transaction
     -->
-- 
GitLab