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();
}
}