You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by hl...@apache.org on 2008/09/08 23:06:06 UTC

svn commit: r693271 - in /tapestry/tapestry5/trunk: tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ tapestry-hibernate/src/main/java/org/apache/tapestry5/internal/hibernate/ tapestry-hibernate/src/main/resources/org/apache/tapestry5...

Author: hlship
Date: Mon Sep  8 14:06:04 2008
New Revision: 693271

URL: http://svn.apache.org/viewvc?rev=693271&view=rev
Log:
TAPESTRY-2630: EntityPersistentFieldStrategy converts entity PKs to strings and back unnecessarily

Added:
    tapestry/tapestry5/trunk/tapestry-hibernate/src/main/java/org/apache/tapestry5/internal/hibernate/PersistedEntity.java
Modified:
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AbstractSessionPersistentFieldStrategy.java
    tapestry/tapestry5/trunk/tapestry-hibernate/src/main/java/org/apache/tapestry5/internal/hibernate/EntityPersistentFieldStrategy.java
    tapestry/tapestry5/trunk/tapestry-hibernate/src/main/java/org/apache/tapestry5/internal/hibernate/HibernateMessages.java
    tapestry/tapestry5/trunk/tapestry-hibernate/src/main/resources/org/apache/tapestry5/internal/hibernate/HibernateStrings.properties
    tapestry/tapestry5/trunk/tapestry-hibernate/src/test/java/org/apache/tapestry5/internal/hibernate/EntityPersistentFieldStrategyTest.java

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AbstractSessionPersistentFieldStrategy.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AbstractSessionPersistentFieldStrategy.java?rev=693271&r1=693270&r2=693271&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AbstractSessionPersistentFieldStrategy.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AbstractSessionPersistentFieldStrategy.java Mon Sep  8 14:06:04 2008
@@ -53,7 +53,12 @@
 
         for (String name : session.getAttributeNames(fullPrefix))
         {
-            PersistentFieldChange change = buildChange(name, session.getAttribute(name));
+            Object persistedValue = session.getAttribute(name);
+
+            Object applicationValue = persistedValue == null ? null : convertPersistedToApplicationValue(
+                    persistedValue);
+
+            PersistentFieldChange change = buildChange(name, applicationValue);
 
             result.add(change);
 
@@ -88,18 +93,15 @@
     {
     }
 
-    private PersistentFieldChange buildChange(String name, Object attribute)
+    private PersistentFieldChange buildChange(String name, Object newValue)
     {
-        // TODO: Regexp is probably too expensive for what we need here. Maybe an IOC InternalUtils
-        // method for this purpose?
-
         String[] chunks = name.split(":");
 
         // Will be empty string for the root component
         String componentId = chunks[2];
         String fieldName = chunks[3];
 
-        return new PersistentFieldChangeImpl(componentId, fieldName, attribute);
+        return new PersistentFieldChangeImpl(componentId, fieldName, newValue);
     }
 
     public final void postChange(String pageName, String componentId, String fieldName,
@@ -108,6 +110,8 @@
         notBlank(pageName, "pageName");
         notBlank(fieldName, "fieldName");
 
+        Object persistedValue = newValue == null ? null : convertApplicationValueToPersisted(newValue);
+
         StringBuilder builder = new StringBuilder(prefix);
         builder.append(pageName);
         builder.append(':');
@@ -117,14 +121,41 @@
         builder.append(':');
         builder.append(fieldName);
 
-        Session session = request.getSession(newValue != null);
+        Session session = request.getSession(persistedValue != null);
 
         // TAPESTRY-2308: The session will be false when newValue is null and the session
         // does not already exist.
 
         if (session != null)
         {
-            session.setAttribute(builder.toString(), newValue);
+            session.setAttribute(builder.toString(), persistedValue);
         }
     }
+
+    /**
+     * Hook that allows a value to be converted as it is written to the session. Passed the new value provided by the
+     * application, returns the object to be stored in the session. This implementation simply returns the provided
+     * value.
+     *
+     * @param newValue non-null value
+     * @return persisted value
+     * @see #convertPersistedToApplicationValue(Object)
+     */
+    protected Object convertApplicationValueToPersisted(Object newValue)
+    {
+        return newValue;
+    }
+
+    /**
+     * Converts a persisted value stored in the session back into an application value.   This implementation returns
+     * the persisted value as is.
+     *
+     * @param persistedValue non-null persisted value
+     * @return application value
+     * @see #convertPersistedToApplicationValue(Object)
+     */
+    protected Object convertPersistedToApplicationValue(Object persistedValue)
+    {
+        return persistedValue;
+    }
 }

Modified: tapestry/tapestry5/trunk/tapestry-hibernate/src/main/java/org/apache/tapestry5/internal/hibernate/EntityPersistentFieldStrategy.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-hibernate/src/main/java/org/apache/tapestry5/internal/hibernate/EntityPersistentFieldStrategy.java?rev=693271&r1=693270&r2=693271&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-hibernate/src/main/java/org/apache/tapestry5/internal/hibernate/EntityPersistentFieldStrategy.java (original)
+++ tapestry/tapestry5/trunk/tapestry-hibernate/src/main/java/org/apache/tapestry5/internal/hibernate/EntityPersistentFieldStrategy.java Mon Sep  8 14:06:04 2008
@@ -15,119 +15,49 @@
 package org.apache.tapestry5.internal.hibernate;
 
 import org.apache.tapestry5.internal.services.AbstractSessionPersistentFieldStrategy;
-import org.apache.tapestry5.internal.services.PersistentFieldChangeImpl;
-import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
-import org.apache.tapestry5.ioc.internal.util.Defense;
-import org.apache.tapestry5.ioc.services.TypeCoercer;
-import org.apache.tapestry5.services.PersistentFieldChange;
-import org.apache.tapestry5.services.PersistentFieldStrategy;
 import org.apache.tapestry5.services.Request;
 import org.hibernate.HibernateException;
 import org.hibernate.Session;
-import org.hibernate.metadata.ClassMetadata;
 
 import java.io.Serializable;
-import java.util.Collection;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
 
 /**
  * Persists Hibernate entities by storing their id in the session.
+ *
+ * @see org.apache.tapestry5.internal.hibernate.PersistedEntity
  */
-public class EntityPersistentFieldStrategy implements PersistentFieldStrategy
+public class EntityPersistentFieldStrategy extends AbstractSessionPersistentFieldStrategy
 {
-    private static final Pattern KEY_PATTERN = Pattern.compile("^([^:]+):([^:]+):(.+)$");
-
-    private final PersistentFieldStrategy strategy;
     private final Session session;
-    private final TypeCoercer typeCoercer;
 
-    public EntityPersistentFieldStrategy(Session session, TypeCoercer typeCoercer, Request request)
+    public EntityPersistentFieldStrategy(Session session, Request request)
     {
-        strategy = new EntityStrategy(request);
-        this.session = session;
-        this.typeCoercer = typeCoercer;
-    }
+        super("entity:", request);
 
-    public void discardChanges(String pageName)
-    {
-        strategy.discardChanges(pageName);
+        this.session = session;
     }
 
-    public Collection<PersistentFieldChange> gatherFieldChanges(String pageName)
+    @Override
+    protected Object convertApplicationValueToPersisted(Object newValue)
     {
-        Collection<PersistentFieldChange> changes = CollectionFactory.newList();
-
-        for (PersistentFieldChange change : strategy.gatherFieldChanges(pageName))
+        try
         {
-            if (change.getValue() == null)
-            {
-                changes.add(change);
-                continue;
-            }
-
-            String key = change.getValue().toString();
-            Matcher matcher = KEY_PATTERN.matcher(key);
-            matcher.matches();
-
-            String entityName = matcher.group(1);
-            String idClassName = matcher.group(2);
-            String stringId = matcher.group(3);
-
-            try
-            {
-                Class<?> idClass = Class.forName(idClassName);
-                Object idObj = typeCoercer.coerce(stringId, idClass);
-
-                Serializable id = Defense.cast(idObj, Serializable.class, "id");
-                Object entity = session.get(entityName, id);
-                changes.add(new PersistentFieldChangeImpl(change.getComponentId(), change.getFieldName(), entity));
-            }
-            catch (ClassNotFoundException e)
-            {
-                throw new RuntimeException(HibernateMessages.badEntityIdType(entityName, idClassName, stringId), e);
-            }
-        }
+            String entityName = session.getEntityName(newValue);
+            Serializable id = session.getIdentifier(newValue);
 
-        return changes;
-    }
-
-    /**
-     * Stores the entity id's as values in the form: entityName:idClass:id
-     */
-    public void postChange(String pageName, String componentId, String fieldName, Object newValue)
-    {
-        if (newValue != null)
+            return new PersistedEntity(entityName, id);
+        }
+        catch (HibernateException ex)
         {
-            try
-            {
-                String entityName = session.getEntityName(newValue);
-                ClassMetadata metadata = session.getSessionFactory().getClassMetadata(newValue.getClass());
-                Serializable id = metadata.getIdentifier(newValue, session.getEntityMode());
-                newValue = entityName + ":" + id.getClass().getCanonicalName() + ":" + typeCoercer.coerce(id,
-                                                                                                          String.class);
-
-            }
-            catch (HibernateException e)
-            {
-                throw new IllegalArgumentException(HibernateMessages.entityNotAttached(newValue), e);
-            }
+            throw new IllegalArgumentException(HibernateMessages.entityNotAttached(newValue), ex);
         }
-
-        strategy.postChange(pageName, componentId, fieldName, newValue);
     }
 
-    /**
-     * We want to store the data in the session normally, we just need to control the values. We also need a separate
-     * instance so that we know it's using the right prefix for the values.
-     */
-    private static final class EntityStrategy extends AbstractSessionPersistentFieldStrategy
+    @Override
+    protected Object convertPersistedToApplicationValue(Object persistedValue)
     {
+        PersistedEntity persisted = (PersistedEntity) persistedValue;
 
-        public EntityStrategy(Request request)
-        {
-            super("entity:", request);
-        }
-
+        return persisted.restore(session);
     }
 }

Modified: tapestry/tapestry5/trunk/tapestry-hibernate/src/main/java/org/apache/tapestry5/internal/hibernate/HibernateMessages.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-hibernate/src/main/java/org/apache/tapestry5/internal/hibernate/HibernateMessages.java?rev=693271&r1=693270&r2=693271&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-hibernate/src/main/java/org/apache/tapestry5/internal/hibernate/HibernateMessages.java (original)
+++ tapestry/tapestry5/trunk/tapestry-hibernate/src/main/java/org/apache/tapestry5/internal/hibernate/HibernateMessages.java Mon Sep  8 14:06:04 2008
@@ -1,4 +1,4 @@
-// Copyright 2007 The Apache Software Foundation
+// Copyright 2007, 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.
@@ -39,9 +39,9 @@
         return MESSAGES.get("configuration-immutable");
     }
 
-    static String badEntityIdType(String entityName, String idClassName, String id)
+    static String sessionPersistedEntityLoadFailure(String entityName, Object id, Throwable cause)
     {
-        return MESSAGES.format("bad-entity-id-type", entityName, idClassName, id);
+        return MESSAGES.format("session-persisted-entity-load-failure", entityName, id, cause);
     }
 
     static String entityNotAttached(Object entity)

Added: tapestry/tapestry5/trunk/tapestry-hibernate/src/main/java/org/apache/tapestry5/internal/hibernate/PersistedEntity.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-hibernate/src/main/java/org/apache/tapestry5/internal/hibernate/PersistedEntity.java?rev=693271&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-hibernate/src/main/java/org/apache/tapestry5/internal/hibernate/PersistedEntity.java (added)
+++ tapestry/tapestry5/trunk/tapestry-hibernate/src/main/java/org/apache/tapestry5/internal/hibernate/PersistedEntity.java Mon Sep  8 14:06:04 2008
@@ -0,0 +1,53 @@
+//  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.tapestry5.internal.hibernate;
+
+import org.hibernate.Session;
+
+import java.io.Serializable;
+
+/**
+ * Encapsulates a Hibernate entity name with an entity id.
+ */
+public class PersistedEntity implements Serializable
+{
+    private final String entityName;
+
+    private final Serializable id;
+
+    public PersistedEntity(String entityName, Serializable id)
+    {
+        this.entityName = entityName;
+        this.id = id;
+    }
+
+    Object restore(Session session)
+    {
+        try
+        {
+            return session.get(entityName, id);
+        }
+        catch (Exception ex)
+        {
+            throw new RuntimeException(HibernateMessages.sessionPersistedEntityLoadFailure(entityName, id, ex));
+        }
+    }
+
+    @Override
+    public String toString()
+    {
+        return String.format("<PersistedEntity: %s(%s)>", entityName, id);
+    }
+}

Modified: tapestry/tapestry5/trunk/tapestry-hibernate/src/main/resources/org/apache/tapestry5/internal/hibernate/HibernateStrings.properties
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-hibernate/src/main/resources/org/apache/tapestry5/internal/hibernate/HibernateStrings.properties?rev=693271&r1=693270&r2=693271&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-hibernate/src/main/resources/org/apache/tapestry5/internal/hibernate/HibernateStrings.properties (original)
+++ tapestry/tapestry5/trunk/tapestry-hibernate/src/main/resources/org/apache/tapestry5/internal/hibernate/HibernateStrings.properties Mon Sep  8 14:06:04 2008
@@ -1,4 +1,4 @@
-# Copyright 2007 The Apache Software Foundation
+# Copyright 2007, 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.
@@ -15,6 +15,6 @@
 startup-timing=Hibernate startup: %,d ms to configure, %,d ms overall.
 entity-catalog=Configured Hibernate entities: %s
 configuration-immutable=The Hibernate configuration is now immutable since the SessionFactory has already been created.
-bad-entity-id-type=Failed to load the entity id class while loading a persisted entity. entity: %s, id class: %s, id: %s
+session-persisted-entity-load-failure=Failed to load session-persisted entity %s(%s): %s
 entity-not-attached=Failed persisting an entity in the session. Only entities attached to a Hibernate Session can be persisted. entity: %s
 commit-transaction-interceptor=<Hibernate Transaction interceptor for %s(%s)>

Modified: tapestry/tapestry5/trunk/tapestry-hibernate/src/test/java/org/apache/tapestry5/internal/hibernate/EntityPersistentFieldStrategyTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-hibernate/src/test/java/org/apache/tapestry5/internal/hibernate/EntityPersistentFieldStrategyTest.java?rev=693271&r1=693270&r2=693271&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-hibernate/src/test/java/org/apache/tapestry5/internal/hibernate/EntityPersistentFieldStrategyTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-hibernate/src/test/java/org/apache/tapestry5/internal/hibernate/EntityPersistentFieldStrategyTest.java Mon Sep  8 14:06:04 2008
@@ -24,19 +24,25 @@
 {
     public void not_an_entity()
     {
+        String nonEntity = "foo";
         Session session = newMock(Session.class);
-        EntityPersistentFieldStrategy strategy = new EntityPersistentFieldStrategy(session, null, null);
+        EntityPersistentFieldStrategy strategy = new EntityPersistentFieldStrategy(session, null);
+
+        expect(session.getEntityName(nonEntity)).andThrow(new HibernateException("error"));
 
-        expect(session.getEntityName("foo")).andThrow(new HibernateException("error"));
         replay();
+
         try
         {
-            strategy.postChange(null, null, null, "foo");
-            fail("did not throw");
+            strategy.postChange("pageName", "", "fieldName", nonEntity);
+
+            unreachable();
         }
-        catch (IllegalArgumentException e)
+        catch (IllegalArgumentException ex)
         {
+            assertEquals(ex.getMessage(), "Failed persisting an entity in the session. Only entities attached to a Hibernate Session can be persisted. entity: foo");
         }
+
         verify();
     }
 }