Hi,
Am 07.05.2014 22:44, schrieb Thiago H de Paula Figueiredo:
On Wed, 07 May 2014 03:41:46 -0300, Jochen Kemnade
<jochen.kemn...@eddyson.de> wrote:
Hi,
Hi!
I just re-discovered the ImmutableSessionPersistedObject annotation.
Maybe we can leverage that?
I think we could use both approaches, as we cannot add the annotation to
classes we don't own.
I'm still undecided how to handle this issue. To get started, I created
and attached a simple patch that downgrades the write lock to a read
lock if the attribute's class is a String, a primitive wrapper type or
has the ImmutableSessionPersistedObject annotation.
This is of course not very flexible but should work in a lot of
situations. And we can always extend the list of immutable classes later.
However, if we want a more flexible approach, I guess the best way to go
would be a SessionPersistedObjectAnalyzer2 interface, with an added
boolean isMutable(T sessionPersistedObject) method.
Any thoughts?
Jochen
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/SessionImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/SessionImpl.java
index 7829285..dcf65f1 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/SessionImpl.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/SessionImpl.java
@@ -14,6 +14,7 @@
package org.apache.tapestry5.internal.services;
+import org.apache.tapestry5.annotations.ImmutableSessionPersistedObject;
import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
import org.apache.tapestry5.ioc.internal.util.InternalUtils;
import org.apache.tapestry5.ioc.services.PerthreadManager;
@@ -21,9 +22,11 @@ import org.apache.tapestry5.services.Session;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
+
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
+import java.util.Set;
/**
* A thin wrapper around {@link HttpSession}.
@@ -36,8 +39,15 @@ public class SessionImpl implements Session
private boolean invalidated = false;
+ private boolean mutableObjectWasRead = false;
+
private final SessionLock lock;
+ @SuppressWarnings("rawtypes")
+ private final static Set<Class> immutableClasses = Collections.unmodifiableSet(
+ CollectionFactory.<Class, Class>newSet(String.class, Character.class, Byte.class,
+ Integer.class, Long.class, Short.class, Double.class, Boolean.class));
+
public SessionImpl(HttpServletRequest request, HttpSession session, SessionLock lock)
{
this.request = request;
@@ -47,9 +57,40 @@ public class SessionImpl implements Session
public Object getAttribute(String name)
{
+ // We acquire the write lock as a precaution because the object that is to be read might be mutable
lock.acquireWriteLock();
- return session.getAttribute(name);
+ Object attributeValue = session.getAttribute(name);
+
+ // If no mutable object was read from the session before, we may be able to release the write lock
+ if (!mutableObjectWasRead)
+ {
+ if (!isMutableObject(attributeValue))
+ {
+ lock.downgradeWriteLockToReadLock();
+ } else
+ {
+ mutableObjectWasRead = true;
+ }
+ }
+ return attributeValue;
+ }
+
+ private static boolean isMutableObject(Object object)
+ {
+ if (object == null){
+ return false;
+ }
+ Class<?> objectClass = object.getClass();
+ if (objectClass.getAnnotation(ImmutableSessionPersistedObject.class) != null)
+ {
+ return false;
+ }
+ if (immutableClasses.contains(objectClass))
+ {
+ return false;
+ }
+ return true;
}
public List<String> getAttributeNames()
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/SessionLock.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/SessionLock.java
index d234bd4..be1cdd9 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/SessionLock.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/SessionLock.java
@@ -33,4 +33,9 @@ public interface SessionLock
* this may block for a while. Does nothing if the write lock is already held by this thread.
*/
void acquireWriteLock();
+
+ /**
+ * Releases the exclusive write lock and acquires the read lock instead.
+ */
+ void downgradeWriteLockToReadLock();
}
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/TapestrySessionFactoryImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/TapestrySessionFactoryImpl.java
index bc221a6..0faccfa 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/TapestrySessionFactoryImpl.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/TapestrySessionFactoryImpl.java
@@ -53,6 +53,10 @@ public class TapestrySessionFactoryImpl implements TapestrySessionFactory
public void acquireWriteLock()
{
}
+
+ public void downgradeWriteLockToReadLock()
+ {
+ }
};
private class SessionLockImpl implements SessionLock
@@ -112,11 +116,24 @@ public class TapestrySessionFactoryImpl implements TapestrySessionFactory
{
public void run()
{
- // This is the only way a write lock is unlocked, so no check is needed.
- lock.writeLock().unlock();
+ // The write lock may have been released, if downgraded to a read lock.
+ if (isWriteLocked())
+ {
+ lock.writeLock().unlock();
+ }
}
});
}
+
+ @Override
+ public void downgradeWriteLockToReadLock()
+ {
+ lock.writeLock().unlock();
+
+ // During this window, no lock is held, and the next call may block.
+
+ acquireReadLock();
+ }
}
public TapestrySessionFactoryImpl(
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tapestry.apache.org
For additional commands, e-mail: dev-h...@tapestry.apache.org