Author: dadams
Date: Sat Mar  8 07:23:21 2008
New Revision: 634989

URL: http://svn.apache.org/viewvc?rev=634989&view=rev
Log:
TAPESTRY-1653: Provide automatic ValueEncoders for Hibernate entities

Added:
    
tapestry/tapestry5/trunk/tapestry-hibernate/src/main/java/org/apache/tapestry/internal/hibernate/HibernateEntityValueEncoder.java
    tapestry/tapestry5/trunk/tapestry-hibernate/src/site/apt/userguide.apt
    
tapestry/tapestry5/trunk/tapestry-hibernate/src/test/java/org/example/app0/pages/EncodeEntities.java
    
tapestry/tapestry5/trunk/tapestry-hibernate/src/test/webapp/EncodeEntities.tml
Modified:
    
tapestry/tapestry5/trunk/tapestry-hibernate/src/main/java/org/apache/tapestry/hibernate/HibernateModule.java
    tapestry/tapestry5/trunk/tapestry-hibernate/src/site/site.xml
    
tapestry/tapestry5/trunk/tapestry-hibernate/src/test/java/org/apache/tapestry/hibernate/integration/TapestryHibernateIntegrationTests.java
    
tapestry/tapestry5/trunk/tapestry-hibernate/src/test/java/org/example/app0/entities/User.java
    
tapestry/tapestry5/trunk/tapestry-hibernate/src/test/java/org/example/app0/pages/Start.java
    
tapestry/tapestry5/trunk/tapestry-hibernate/src/test/resources/hibernate.cfg.xml
    tapestry/tapestry5/trunk/tapestry-hibernate/src/test/webapp/Start.tml

Modified: 
tapestry/tapestry5/trunk/tapestry-hibernate/src/main/java/org/apache/tapestry/hibernate/HibernateModule.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-hibernate/src/main/java/org/apache/tapestry/hibernate/HibernateModule.java?rev=634989&r1=634988&r2=634989&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-hibernate/src/main/java/org/apache/tapestry/hibernate/HibernateModule.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-hibernate/src/main/java/org/apache/tapestry/hibernate/HibernateModule.java
 Sat Mar  8 07:23:21 2008
@@ -14,12 +14,17 @@
 
 package org.apache.tapestry.hibernate;
 
+import org.apache.tapestry.ValueEncoder;
 import org.apache.tapestry.internal.InternalConstants;
 import org.apache.tapestry.internal.hibernate.DefaultHibernateConfigurer;
+import org.apache.tapestry.internal.hibernate.HibernateEntityValueEncoder;
 import org.apache.tapestry.internal.hibernate.HibernateSessionManagerImpl;
 import org.apache.tapestry.internal.hibernate.HibernateSessionSourceImpl;
 import org.apache.tapestry.internal.hibernate.PackageNameHibernateConfigurer;
 import org.apache.tapestry.ioc.Configuration;
+import org.apache.tapestry.ioc.MappedConfiguration;
+import org.apache.tapestry.ioc.ObjectLocator;
+
 import static org.apache.tapestry.ioc.IOCConstants.PERTHREAD_SCOPE;
 import org.apache.tapestry.ioc.OrderedConfiguration;
 import org.apache.tapestry.ioc.annotations.Inject;
@@ -30,11 +35,15 @@
 import org.apache.tapestry.ioc.services.PerthreadManager;
 import org.apache.tapestry.ioc.services.PropertyShadowBuilder;
 import org.apache.tapestry.ioc.services.RegistryShutdownHub;
+import org.apache.tapestry.ioc.services.TypeCoercer;
 import org.apache.tapestry.services.AliasContribution;
+import org.apache.tapestry.services.ValueEncoderFactory;
 import org.hibernate.Session;
+import org.hibernate.mapping.PersistentClass;
 import org.slf4j.Logger;
 
 import java.util.Collection;
+import java.util.Iterator;
 import java.util.List;
 
 public class HibernateModule
@@ -129,4 +138,30 @@
         config.add("PackageName", new 
PackageNameHibernateConfigurer(packageManager, classNameLocator));
     }
 
+    /**
+     * Contributes [EMAIL PROTECTED] ValueEncoderFactory}s for all registered 
Hibernate entity classes. Encoding and decoding are based
+     * on the id property value of the entity using type coercion. Hence, if 
the id can be coerced to a String and back then
+     * the entity can be coerced.
+     */
+    @SuppressWarnings("unchecked")
+    public static void contributeValueEncoderSource(MappedConfiguration<Class, 
ValueEncoderFactory> configuration,
+                                                    final 
HibernateSessionSource sessionSource,
+                                                    final Session session,
+                                                    final TypeCoercer 
typeCoercer)
+    {
+       org.hibernate.cfg.Configuration config = 
sessionSource.getConfiguration();
+       Iterator<PersistentClass> mappings = config.getClassMappings();
+       while(mappings.hasNext()) {
+               final PersistentClass persistentClass = mappings.next();
+               final Class entityClass = persistentClass.getMappedClass();
+                       
+                       ValueEncoderFactory factory = new ValueEncoderFactory() 
{
+                               public ValueEncoder create(Class type) {
+                                       return new 
HibernateEntityValueEncoder(entityClass, persistentClass, session, typeCoercer);
+                               }
+                       };
+                       
+                       configuration.add(entityClass, factory);
+       }
+    }
 }

Added: 
tapestry/tapestry5/trunk/tapestry-hibernate/src/main/java/org/apache/tapestry/internal/hibernate/HibernateEntityValueEncoder.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-hibernate/src/main/java/org/apache/tapestry/internal/hibernate/HibernateEntityValueEncoder.java?rev=634989&view=auto
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-hibernate/src/main/java/org/apache/tapestry/internal/hibernate/HibernateEntityValueEncoder.java
 (added)
+++ 
tapestry/tapestry5/trunk/tapestry-hibernate/src/main/java/org/apache/tapestry/internal/hibernate/HibernateEntityValueEncoder.java
 Sat Mar  8 07:23:21 2008
@@ -0,0 +1,59 @@
+// Copyright 2008 The Apache Software Foundation
+//
+// 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 org.apache.tapestry.internal.hibernate;
+
+import java.io.Serializable;
+
+import org.apache.tapestry.ValueEncoder;
+import org.apache.tapestry.ioc.internal.util.Defense;
+import org.apache.tapestry.ioc.services.TypeCoercer;
+import org.hibernate.Session;
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.mapping.Property;
+import org.hibernate.property.Getter;
+
+public final class HibernateEntityValueEncoder<E> implements ValueEncoder<E> {
+       private final Class<E> _entityClass;
+       private final PersistentClass _persistentClass;
+       private final Session _session;
+       private final TypeCoercer _typeCoercer;
+       private final Getter _idGetter;
+       
+       public HibernateEntityValueEncoder(Class<E> entityClass, 
PersistentClass persistentClass, Session session, TypeCoercer typeCoercer) {
+               super();
+               _entityClass = entityClass;
+               _persistentClass = persistentClass;
+               _session = session;
+               _typeCoercer = typeCoercer;
+               
+               Property property = _persistentClass.getIdentifierProperty();
+               _idGetter = 
property.getPropertyAccessor(_entityClass).getGetter(_entityClass, 
property.getName());
+       }
+               
+       public String toClient(E value) {
+               Object id = _idGetter.get(value);
+               return _typeCoercer.coerce(id, String.class);
+       }
+
+       @SuppressWarnings("unchecked")
+       public E toValue(String clientValue) {
+               Class<?> idType = _idGetter.getReturnType();
+               
+               Object id = _typeCoercer.coerce(clientValue, idType);
+               Serializable ser = Defense.cast(id, Serializable.class, "id");
+               return (E)_session.get(_entityClass, ser);
+       }
+       
+}

Added: tapestry/tapestry5/trunk/tapestry-hibernate/src/site/apt/userguide.apt
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-hibernate/src/site/apt/userguide.apt?rev=634989&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-hibernate/src/site/apt/userguide.apt 
(added)
+++ tapestry/tapestry5/trunk/tapestry-hibernate/src/site/apt/userguide.apt Sat 
Mar  8 07:23:21 2008
@@ -0,0 +1,31 @@
+  ----
+  User Guide
+  ----
+  
+Entity value encoding
+
+  Value encoders are automatically created for all mapped Hibernate entity 
types. This is done by encoding the entity as it's 
+  id (coerced to a String) and decoding the entity by looking it up in the 
Hibernate Session using the encoded id. Consider
+  the following:
+  
++----+
+public class ViewPerson {
+  @Property
+  private Person _person;
+  
+  void onActivate(Person person)
+  {
+    _person = person;
+  }
+}
++----+   
+
++----+
+<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd";>
+<body>
+  The person's name is: ${person.name}
+</body>
+</html>
++----+
+
+  Accessing the page as <</viewperson/152>> would load the Person entity with 
id 152 and use that as the page context.

Modified: tapestry/tapestry5/trunk/tapestry-hibernate/src/site/site.xml
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-hibernate/src/site/site.xml?rev=634989&r1=634988&r2=634989&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-hibernate/src/site/site.xml (original)
+++ tapestry/tapestry5/trunk/tapestry-hibernate/src/site/site.xml Sat Mar  8 
07:23:21 2008
@@ -40,6 +40,7 @@
     <menu name="Quick Links">
       <item name="About" href="index.html"/>
       <item name="Configuration" href="conf.html"/>
+      <item name="User guide" href="userguide.html" />
       <item name="Download" href="http://tapestry.apache.org/download.html"/>
     </menu>
         

Modified: 
tapestry/tapestry5/trunk/tapestry-hibernate/src/test/java/org/apache/tapestry/hibernate/integration/TapestryHibernateIntegrationTests.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-hibernate/src/test/java/org/apache/tapestry/hibernate/integration/TapestryHibernateIntegrationTests.java?rev=634989&r1=634988&r2=634989&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-hibernate/src/test/java/org/apache/tapestry/hibernate/integration/TapestryHibernateIntegrationTests.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-hibernate/src/test/java/org/apache/tapestry/hibernate/integration/TapestryHibernateIntegrationTests.java
 Sat Mar  8 07:23:21 2008
@@ -25,12 +25,18 @@
         super("src/test/webapp");
     }
 
-    /** Only needed until actual integration tests are put in. Just proves the 
integration
-     * tests are set up correctly.
-     */
-    public void test_placeholder() throws Exception {
-               open("/");
-               // just make sure we can get the hibernate Session
-               assertTrue(getText("//[EMAIL PROTECTED]'session']").length() > 
0);
+       public void test_valueencode_all_entity_types() throws Exception {
+               open("/encodeentities");
+               
+               assertEquals(0, getText("//[EMAIL PROTECTED]'name']").length());
+
+               // need to create an entity in order to link with one
+               clickAndWait("//[EMAIL PROTECTED]'createentity']");
+               assertEquals("name", getText("//[EMAIL PROTECTED]'name']"));
+               
+               // should return null for missing objects
+               open("/encodeentities/9999");
+               assertEquals(0, getText("//[EMAIL PROTECTED]'name']").length());
        }
+
 }

Modified: 
tapestry/tapestry5/trunk/tapestry-hibernate/src/test/java/org/example/app0/entities/User.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-hibernate/src/test/java/org/example/app0/entities/User.java?rev=634989&r1=634988&r2=634989&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-hibernate/src/test/java/org/example/app0/entities/User.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-hibernate/src/test/java/org/example/app0/entities/User.java
 Sat Mar  8 07:23:21 2008
@@ -22,67 +22,68 @@
 @Entity
 public class User
 {
+       // NOTE: Hibernate doesn't understand the '_' syntax. It will end up 
putting underscores on all the properties
     @Id @GeneratedValue
-    private Long _id;
+    private Long id;
 
-    private String _firstName;
+    private String firstName;
 
-    private String _lastName;
+    private String lastName;
 
-    private String _email;
+    private String email;
 
-    private String _encodedPassword;
+    private String encodedPassword;
 
     @Version
-    private int _version;
+    private int version;
 
     public String getEmail()
     {
-        return _email;
+        return email;
     }
 
     public String getEncodedPassword()
     {
-        return _encodedPassword;
+        return encodedPassword;
     }
 
     public String getFirstName()
     {
-        return _firstName;
+        return firstName;
     }
 
     public Long getId()
     {
-        return _id;
+        return id;
     }
 
     public String getLastName()
     {
-        return _lastName;
+        return lastName;
     }
 
     public int getVersion()
     {
-        return _version;
+        return version;
     }
 
     public void setEmail(String email)
     {
-        _email = email;
+        this.email = email;
     }
 
     public void setEncodedPassword(String encodedPassword)
     {
-        _encodedPassword = encodedPassword;
+        this.encodedPassword = encodedPassword;
     }
 
     public void setFirstName(String firstName)
     {
-        _firstName = firstName;
+        this.firstName = firstName;
     }
 
     public void setLastName(String lastName)
     {
-        _lastName = lastName;
+        this.lastName = lastName;
     }
 }

Added: 
tapestry/tapestry5/trunk/tapestry-hibernate/src/test/java/org/example/app0/pages/EncodeEntities.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-hibernate/src/test/java/org/example/app0/pages/EncodeEntities.java?rev=634989&view=auto
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-hibernate/src/test/java/org/example/app0/pages/EncodeEntities.java
 (added)
+++ 
tapestry/tapestry5/trunk/tapestry-hibernate/src/test/java/org/example/app0/pages/EncodeEntities.java
 Sat Mar  8 07:23:21 2008
@@ -0,0 +1,37 @@
+package org.example.app0.pages;
+
+import java.util.List;
+
+import org.apache.tapestry.annotations.Property;
+import org.apache.tapestry.ioc.annotations.Inject;
+import org.example.app0.entities.User;
+import org.hibernate.Session;
+
+public class EncodeEntities {
+       @Inject
+       @Property
+       private Session _session;
+       
+       @SuppressWarnings("unused")
+       @Property
+       private User _user;
+       
+       void onCreate() {
+               User user = new User();
+               user.setFirstName("name");
+               _session.save(user);
+       }
+
+       @SuppressWarnings("unchecked")
+       User onPassivate() {
+               List<User> users = _session.createQuery("from User").list();
+               if (users.isEmpty())
+                       return null;
+               
+               return users.get(0);
+       }
+       
+       void onActivate(User user) {
+               _user = user;
+       }
+}

Modified: 
tapestry/tapestry5/trunk/tapestry-hibernate/src/test/java/org/example/app0/pages/Start.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-hibernate/src/test/java/org/example/app0/pages/Start.java?rev=634989&r1=634988&r2=634989&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-hibernate/src/test/java/org/example/app0/pages/Start.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-hibernate/src/test/java/org/example/app0/pages/Start.java
 Sat Mar  8 07:23:21 2008
@@ -14,13 +14,6 @@
 
 package org.example.app0.pages;
 
-import org.apache.tapestry.annotations.Property;
-import org.apache.tapestry.ioc.annotations.Inject;
-import org.hibernate.Session;
-
 public class Start {
-       @Property
-       @Inject
-       private Session _session;
        
 }

Modified: 
tapestry/tapestry5/trunk/tapestry-hibernate/src/test/resources/hibernate.cfg.xml
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-hibernate/src/test/resources/hibernate.cfg.xml?rev=634989&r1=634988&r2=634989&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-hibernate/src/test/resources/hibernate.cfg.xml
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-hibernate/src/test/resources/hibernate.cfg.xml
 Sat Mar  8 07:23:21 2008
@@ -23,20 +23,19 @@
 
   <session-factory>
     <property 
name="hibernate.connection.driver_class">org.hsqldb.jdbcDriver</property>
-    <property 
name="hibernate.connection.url">jdbc:hsqldb:file:target/unit-testdb</property>
+    <property name="hibernate.connection.url">jdbc:hsqldb:mem:test</property>
     <property name="hibernate.connection.username">sa</property>
     <property 
name="hibernate.dialect">org.hibernate.dialect.HSQLDialect</property>
     
     <property name="show_sql">true</property>
     <property name="format_sql">true</property>
-    <property name="hbm2ddl.auto">create-drop</property>    
-    
+    <property name="hbm2ddl.auto">update</property>
+
     <property name="hibernate.c3p0.min_size">5</property>
     <property name="hibernate.c3p0.max_size">20</property>
     <property name="hibernate.c3p0.timeout">300</property>
     <property name="hibernate.c3p0.max_statements">50</property>
     <property name="hibernate.c3p0.idle_test_period">3000</property>
-    
   </session-factory>
 
 

Added: 
tapestry/tapestry5/trunk/tapestry-hibernate/src/test/webapp/EncodeEntities.tml
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-hibernate/src/test/webapp/EncodeEntities.tml?rev=634989&view=auto
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-hibernate/src/test/webapp/EncodeEntities.tml 
(added)
+++ 
tapestry/tapestry5/trunk/tapestry-hibernate/src/test/webapp/EncodeEntities.tml 
Sat Mar  8 07:23:21 2008
@@ -0,0 +1,6 @@
+<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd";>
+<body>
+       <p>entity name: <span id="name"><t:if 
test="user">${user.firstName}</t:if></span></p>
+       <p>create entity: <t:eventlink event="create" 
t:id="createentity">create an entity</t:eventlink></p>
+</body>
+</html>
\ No newline at end of file

Modified: tapestry/tapestry5/trunk/tapestry-hibernate/src/test/webapp/Start.tml
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-hibernate/src/test/webapp/Start.tml?rev=634989&r1=634988&r2=634989&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-hibernate/src/test/webapp/Start.tml 
(original)
+++ tapestry/tapestry5/trunk/tapestry-hibernate/src/test/webapp/Start.tml Sat 
Mar  8 07:23:21 2008
@@ -4,6 +4,5 @@
   </head>
   <body>
     <h2>Test application for tapestry-hibernate integration tests</h2>
-    The Hibernate session: <span id="session">${session}</span>
   </body>
 </html>


Reply via email to