You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openwebbeans.apache.org by st...@apache.org on 2015/05/04 11:55:40 UTC
svn commit: r1677572 - in /openwebbeans/trunk:
webbeans-impl/src/main/java/org/apache/webbeans/context/
webbeans-impl/src/main/java/org/apache/webbeans/conversation/
webbeans-impl/src/main/java/org/apache/webbeans/corespi/se/
webbeans-web/src/it/webcdi...
Author: struberg
Date: Mon May 4 09:55:39 2015
New Revision: 1677572
URL: http://svn.apache.org/r1677572
Log:
OWB-1050 finish Conversation rework.
Modified:
openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/context/AbstractContextsService.java
openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/conversation/ConversationImpl.java
openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/conversation/ConversationManager.java
openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/corespi/se/DefaultContextsService.java
openwebbeans/trunk/webbeans-web/src/it/webcdiapp/src/test/java/org/apache/openwebbeans/web/it/ConversationScopedIT.java
openwebbeans/trunk/webbeans-web/src/main/java/org/apache/webbeans/web/context/WebContextsService.java
Modified: openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/context/AbstractContextsService.java
URL: http://svn.apache.org/viewvc/openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/context/AbstractContextsService.java?rev=1677572&r1=1677571&r2=1677572&view=diff
==============================================================================
--- openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/context/AbstractContextsService.java (original)
+++ openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/context/AbstractContextsService.java Mon May 4 09:55:39 2015
@@ -127,39 +127,12 @@ public abstract class AbstractContextsSe
this.supportsConversation = supportConversations;
}
- protected void destroyAllBut(ConversationContext currentConversationCtx)
- {
- Context sessionContext = getCurrentContext(SessionScoped.class, false);
- ConversationManager conversationManager = webBeansContext.getConversationManager();
- Set<ConversationContext> sessionConversations = conversationManager.getSessionConversations(sessionContext, false);
- if (sessionConversations != null)
- {
- for (ConversationContext conversationCtx : sessionConversations)
- {
- if (conversationCtx != currentConversationCtx)
- {
- conversationManager.destroyConversationContext(conversationCtx);
- }
- }
- }
-
- if (currentConversationCtx != null && !currentConversationCtx.getConversation().isTransient())
- {
- currentConversationCtx.getConversation().end();
- }
-
-
- }
-
-
/**
- * Destroy inactive (timed out) and transient conversations.
- * This also will store the currentConversationContext into the session if it is long-running.
+ * Destroy inactive (timed out) conversations.
*/
- public void cleanupConversations(ConversationContext currentConversationContext)
+ public void destroyOutdatedConversations(ConversationContext currentConversationContext)
{
- Context sessionContext = getCurrentContext(SessionScoped.class,
- currentConversationContext != null && !currentConversationContext.getConversation().isTransient());
+ Context sessionContext = getCurrentContext(SessionScoped.class, false);
if (sessionContext != null)
{
ConversationManager conversationManager = webBeansContext.getConversationManager();
@@ -172,19 +145,23 @@ public abstract class AbstractContextsSe
ConversationContext conversationContext = convIt.next();
ConversationImpl conv = conversationContext.getConversation();
- if (conv.isTransient() || conversationManager.conversationTimedOut(conv))
+ if (conversationManager.conversationTimedOut(conv))
{
conversationManager.destroyConversationContext(conversationContext);
convIt.remove();
}
- else
- {
- conv.iDontUseItAnymore();
- }
}
}
}
+ if (currentConversationContext != null)
+ {
+ currentConversationContext.getConversation().iDontUseItAnymore();
+ if (currentConversationContext.getConversation().isTransient())
+ {
+ currentConversationContext.destroy();
+ }
+ }
}
Modified: openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/conversation/ConversationImpl.java
URL: http://svn.apache.org/viewvc/openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/conversation/ConversationImpl.java?rev=1677572&r1=1677571&r2=1677572&view=diff
==============================================================================
--- openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/conversation/ConversationImpl.java (original)
+++ openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/conversation/ConversationImpl.java Mon May 4 09:55:39 2015
@@ -27,10 +27,12 @@ import java.util.logging.Logger;
import javax.enterprise.context.BusyConversationException;
import javax.enterprise.context.Conversation;
+import javax.enterprise.context.ConversationScoped;
import org.apache.webbeans.config.OWBLogConst;
import org.apache.webbeans.config.OpenWebBeansConfiguration;
import org.apache.webbeans.config.WebBeansContext;
+import org.apache.webbeans.context.ConversationContext;
import org.apache.webbeans.logger.WebBeansLoggerFacade;
/**
@@ -65,7 +67,7 @@ public class ConversationImpl implements
*/
private long lastAccessTime = 0L;
- private transient Throwable problemDuringCreation = null;
+ private transient RuntimeException problemDuringCreation = null;
/**
* This instance is under used and by which threads, Atomicinteger would be great but then contract of ContextsService but be enhanced to
@@ -110,6 +112,8 @@ public class ConversationImpl implements
/**
* {@inheritDoc}
+ *
+ * This will also put the current ConversationContext into the SessionContext
*/
@Override
public void begin(String id)
@@ -118,15 +122,6 @@ public class ConversationImpl implements
{
id = webBeansContext.getConversationService().generateConversationId();
}
- else
- {
- //Look at other conversation, that may collate with this is
- final ConversationManager conversationManager = webBeansContext.getConversationManager();
- if (conversationManager.isConversationExistWithGivenId(id))
- {
- throw new IllegalArgumentException("Conversation with id=" + id + " already exists!");
- }
- }
//Transient state
if (isTransient)
@@ -142,10 +137,17 @@ public class ConversationImpl implements
logger.log(Level.WARNING, OWBLogConst.WARN_0003, id);
throw new IllegalStateException();
}
+
+ // now store this conversation in the SessionContext
+ final ConversationManager conversationManager = webBeansContext.getConversationManager();
+ ConversationContext conversationContext = (ConversationContext) webBeansContext.getContextsService().getCurrentContext(ConversationScoped.class);
+ conversationManager.addToConversationStorage(conversationContext, id);
}
/**
* {@inheritDoc}
+ *
+ * This will also remove the current ConversationContext from the SessionContext
*/
@Override
public void end()
@@ -162,6 +164,11 @@ public class ConversationImpl implements
logger.log(Level.WARNING, OWBLogConst.WARN_0004, id);
throw new IllegalStateException(toString() + " has already ended");
}
+
+ // now store this conversation in the SessionContext
+ final ConversationManager conversationManager = webBeansContext.getConversationManager();
+ ConversationContext conversationContext = (ConversationContext) webBeansContext.getContextsService().getCurrentContext(ConversationScoped.class);
+ conversationManager.removeConversationFromStorage(conversationContext);
}
public int iUseIt()
@@ -254,12 +261,12 @@ public class ConversationImpl implements
return "Conversation with id [ " + id + " ]";
}
- public Throwable getProblemDuringCreation()
+ public RuntimeException getProblemDuringCreation()
{
return problemDuringCreation;
}
- public void setProblemDuringCreation(Throwable problemDuringCreation)
+ public void setProblemDuringCreation(RuntimeException problemDuringCreation)
{
this.problemDuringCreation = problemDuringCreation;
}
Modified: openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/conversation/ConversationManager.java
URL: http://svn.apache.org/viewvc/openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/conversation/ConversationManager.java?rev=1677572&r1=1677571&r2=1677572&view=diff
==============================================================================
--- openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/conversation/ConversationManager.java (original)
+++ openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/conversation/ConversationManager.java Mon May 4 09:55:39 2015
@@ -22,7 +22,9 @@ import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
+import javax.enterprise.context.BusyConversationException;
import javax.enterprise.context.Conversation;
+import javax.enterprise.context.NonexistentConversationException;
import javax.enterprise.context.RequestScoped;
import javax.enterprise.context.SessionScoped;
import javax.enterprise.context.spi.Context;
@@ -39,6 +41,7 @@ import org.apache.webbeans.context.Reque
import org.apache.webbeans.context.creational.CreationalContextImpl;
import org.apache.webbeans.logger.WebBeansLoggerFacade;
import org.apache.webbeans.spi.ConversationService;
+import org.apache.webbeans.util.Asserts;
/**
* Manager for the conversations.
@@ -76,8 +79,9 @@ public class ConversationManager
{
ConversationService conversationService = webBeansContext.getConversationService();
- Set<ConversationContext> conversationContexts = getSessionConversations(sessionContext, true);
+ Set<ConversationContext> conversationContexts = getSessionConversations(sessionContext, false);
+ RuntimeException problem = null;
String conversationId = conversationService.getConversationId();
if (conversationId != null && conversationId.length() > 0)
{
@@ -87,15 +91,26 @@ public class ConversationManager
{
if (conversationId.equals(conversationContext.getConversation().getId()))
{
+ if (conversationContext.getConversation().iUseIt() > 1)
+ {
+ problem = new BusyConversationException("Propogated conversation with cid=" +
+ conversationContext.getConversation().getId() +
+ " is used by other request. It creates a new transient conversation");
+ conversationContext.getConversation().setProblemDuringCreation(problem);
+ }
+
return conversationContext;
}
}
}
+
+ problem = new NonexistentConversationException("Propogated conversation with cid=" + conversationId +
+ " cannot be restored. Will create a new transient conversation.");
}
ConversationContext conversationContext = new ConversationContext(webBeansContext);
conversationContext.setActive(true);
- conversationContexts.add(conversationContext);
+ conversationContext.getConversation().setProblemDuringCreation(problem);
webBeansContext.getBeanManagerImpl().fireEvent(getLifecycleEventPayload(conversationContext), InitializedLiteral.INSTANCE_CONVERSATION_SCOPED);
@@ -103,44 +118,45 @@ public class ConversationManager
}
/**
- * Check if a conversation with the given id exists in the session context.
- * @param conversationId conversation id
- * @return true if this conversation exist
+ * Add the given ConversationContext to the SessionContext.
+ * This method usually will get called at {@link Conversation#begin()}.
*/
- public boolean isConversationExistWithGivenId(String conversationId)
+ public void addToConversationStorage(ConversationContext conversationContext, String conversationId)
{
- if (conversationId == null)
- {
- return false;
- }
- Context sessionContext = webBeansContext.getContextsService().getCurrentContext(SessionScoped.class, false);
- if (sessionContext == null)
-
- {
- return false;
- }
-
- Set<ConversationContext> conversationContexts = getSessionConversations(sessionContext, false);
- if (conversationContexts == null)
- {
- return false;
- }
+ Asserts.assertNotNull(conversationId, "conversationId must be set");
+ Context sessionContext = webBeansContext.getContextsService().getCurrentContext(SessionScoped.class);
+ Set<ConversationContext> sessionConversations = getSessionConversations(sessionContext, true);
- for (ConversationContext conversationContext : conversationContexts)
+ // check whether this conversation already exists
+ for (ConversationContext sessionConversation : sessionConversations)
{
- if (conversationId.equals(conversationContext.getConversation().getId()))
+ if (conversationId.equals(sessionConversation.getConversation().getId()))
{
- return true;
+ throw new IllegalArgumentException("Conversation with id=" + conversationId + " already exists!");
}
}
- return false;
+ // if not, then simply add this conversation
+ sessionConversations.add(conversationContext);
}
/**
+ * Remove the given ConversationContext from the SessionContext storage.
+ * This method usually will get called at {@link Conversation#end()} or during cleanup.
+ * Not that this does <b>not</b> destroy the ConversationContext!
+ * @return {@code true} if the conversationContext got removed
+ */
+ public boolean removeConversationFromStorage(ConversationContext conversationContext)
+ {
+ Context sessionContext = webBeansContext.getContextsService().getCurrentContext(SessionScoped.class);
+ Set<ConversationContext> sessionConversations = getSessionConversations(sessionContext, true);
+ return sessionConversations.remove(conversationContext);
+ }
+
+
+ /**
* Gets conversation instance from conversation bean.
* @return conversation instance
- * @deprecated is in
*/
public Conversation getConversationBeanReference()
{
Modified: openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/corespi/se/DefaultContextsService.java
URL: http://svn.apache.org/viewvc/openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/corespi/se/DefaultContextsService.java?rev=1677572&r1=1677571&r2=1677572&view=diff
==============================================================================
--- openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/corespi/se/DefaultContextsService.java (original)
+++ openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/corespi/se/DefaultContextsService.java Mon May 4 09:55:39 2015
@@ -145,7 +145,6 @@ public class DefaultContextsService exte
}
return null;
-
}
@@ -404,7 +403,7 @@ public class DefaultContextsService exte
// cleanup open conversations first
if (supportsConversation)
{
- cleanupConversations();
+ destroyOutdatedConversations(conversationContext.get());
conversationContext.set(null);
conversationContext.remove();
}
@@ -446,11 +445,5 @@ public class DefaultContextsService exte
webBeansContext.getBeanManagerImpl().fireEvent(new Object(), DestroyedLiteral.INSTANCE_SINGLETON_SCOPED);
}
- private void cleanupConversations()
- {
- cleanupConversations(conversationContext.get());
- }
-
-
}
Modified: openwebbeans/trunk/webbeans-web/src/it/webcdiapp/src/test/java/org/apache/openwebbeans/web/it/ConversationScopedIT.java
URL: http://svn.apache.org/viewvc/openwebbeans/trunk/webbeans-web/src/it/webcdiapp/src/test/java/org/apache/openwebbeans/web/it/ConversationScopedIT.java?rev=1677572&r1=1677571&r2=1677572&view=diff
==============================================================================
--- openwebbeans/trunk/webbeans-web/src/it/webcdiapp/src/test/java/org/apache/openwebbeans/web/it/ConversationScopedIT.java (original)
+++ openwebbeans/trunk/webbeans-web/src/it/webcdiapp/src/test/java/org/apache/openwebbeans/web/it/ConversationScopedIT.java Mon May 4 09:55:39 2015
@@ -18,6 +18,7 @@
*/
package org.apache.openwebbeans.web.it;
+import javax.enterprise.context.NonexistentConversationException;
import javax.servlet.http.HttpServletResponse;
import org.apache.http.impl.client.DefaultHttpClient;
@@ -28,7 +29,7 @@ public class ConversationScopedIT extend
{
@Test
- public void testRequestScoped() throws Exception
+ public void testStandardConversation() throws Exception
{
DefaultHttpClient client = new DefaultHttpClient();
@@ -99,6 +100,70 @@ public class ConversationScopedIT extend
+ @Test
+ public void testSessionInvalidationDuringConversation() throws Exception
+ {
+ DefaultHttpClient client = new DefaultHttpClient();
+
+ // GET http://localhost:8089/webbeanswebCdiApp/conversation/info etc
+
+ ConversationInfo previousInfo;
+ {
+ String content = httpGet(client, "conversation/info", HttpServletResponse.SC_OK);
+ ConversationInfo info = assertConversationInfo(content, "null", true, "empty", null);
+ previousInfo = info;
+ }
+
+ {
+ // once again, we like to make sure we really get different instances
+ String content = httpGet(client, "conversation/info", HttpServletResponse.SC_OK);
+ ConversationInfo info = assertConversationInfo(content, "null", true, "empty", null);
+ Assert.assertTrue(!info.instanceHash.equals(previousInfo.instanceHash));
+ }
+
+ {
+ // now we begin the transaction
+ String content = httpGet(client, "conversation/begin", HttpServletResponse.SC_OK);
+ ConversationInfo info = assertConversationInfo(content, null, false, "empty", null);
+ Assert.assertTrue(!info.instanceHash.equals(previousInfo.instanceHash));
+ Assert.assertTrue(!"null".equals(info.cid));
+ previousInfo = info;
+ }
+
+ {
+ // let's look what we got.
+ String content = httpGet(client, "conversation/info?cid=" + previousInfo.cid, HttpServletResponse.SC_OK);
+ ConversationInfo info = assertConversationInfo(content, previousInfo.cid, false, "empty", previousInfo.instanceHash);
+ previousInfo = info;
+ }
+
+ {
+ // and set a value
+ String content = httpGet(client, "conversation/set?cid=" + previousInfo.cid + "&content=full", HttpServletResponse.SC_OK);
+ ConversationInfo info = assertConversationInfo(content, previousInfo.cid, false, "full", previousInfo.instanceHash);
+ previousInfo = info;
+ }
+ String oldCid = previousInfo.cid;
+
+ {
+ // and now we invalidate the session
+ // For the first request we should STILL get the old values as per spec
+ // the Conversation only gets destroyed at the end of the Request
+ // But the Conversation got ended (now is transient) and the cid is null
+ String content = httpGet(client, "conversation/invalidateSession?cid=" + previousInfo.cid, HttpServletResponse.SC_OK);
+ ConversationInfo info = assertConversationInfo(content, "null", true, "full", previousInfo.instanceHash);
+ previousInfo = info;
+ }
+
+
+ {
+ // and look again with the same
+ String content = httpGet(client, "conversation/info?cid=" + oldCid, HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+ Assert.assertTrue(content.contains(NonexistentConversationException.class.getName()));
+ }
+ }
+
+
private ConversationInfo assertConversationInfo(String content, String expectedCid, boolean expectedIsTransient, String expectedValue, Object expectedInstanceHash)
{
Assert.assertNotNull(content);
Modified: openwebbeans/trunk/webbeans-web/src/main/java/org/apache/webbeans/web/context/WebContextsService.java
URL: http://svn.apache.org/viewvc/openwebbeans/trunk/webbeans-web/src/main/java/org/apache/webbeans/web/context/WebContextsService.java?rev=1677572&r1=1677571&r2=1677572&view=diff
==============================================================================
--- openwebbeans/trunk/webbeans-web/src/main/java/org/apache/webbeans/web/context/WebContextsService.java (original)
+++ openwebbeans/trunk/webbeans-web/src/main/java/org/apache/webbeans/web/context/WebContextsService.java Mon May 4 09:55:39 2015
@@ -35,11 +35,9 @@ import org.apache.webbeans.logger.WebBea
import org.apache.webbeans.web.intercept.RequestScopedBeanInterceptorHandler;
import javax.enterprise.context.ApplicationScoped;
-import javax.enterprise.context.BusyConversationException;
import javax.enterprise.context.ContextException;
import javax.enterprise.context.ConversationScoped;
import javax.enterprise.context.Dependent;
-import javax.enterprise.context.NonexistentConversationException;
import javax.enterprise.context.RequestScoped;
import javax.enterprise.context.SessionScoped;
import javax.enterprise.context.spi.Context;
@@ -63,13 +61,6 @@ public class WebContextsService extends
private static final String OWB_SESSION_CONTEXT_ATTRIBUTE_NAME = "openWebBeansSessionContext";
- /**
- * This request attribute gets set when an illegal conversation id or busy conversation access
- * gets discovered. In that case we need to throw an Exception and provide
- * a fresh transient conversation. This attribute gets set when exactly that happens.
- */
- private static final String OWB_REQUEST_TRANSIENT_CONVERSATION_ATTRIBUTE_NAME = "org.apache.webbeans.web.transient_conversation";
-
/**Current request context*/
protected static ThreadLocal<ServletRequestContext> requestContexts = null;
@@ -246,7 +237,7 @@ public class WebContextsService extends
}
else if(scopeType.equals(ConversationScoped.class))
{
- return getConversationContext(true);
+ return getConversationContext(true, false);
}
else if(scopeType.equals(Dependent.class))
{
@@ -353,7 +344,7 @@ public class WebContextsService extends
// cleanup open conversations first
if (supportsConversation)
{
- cleanupConversations(conversationContexts.get());
+ destroyOutdatedConversations(conversationContexts.get());
}
//Get context
@@ -479,17 +470,18 @@ public class WebContextsService extends
{
// get all conversations stored in the Session and destroy them
// also set the current conversation (if any) to transient
- destroyAllBut(getConversationContext(true));
+ ConversationContext currentConversationContext = getConversationContext(true, true);
+ if (currentConversationContext != null && !currentConversationContext.getConversation().isTransient())
+ {
+ // an active conversation will now be set to transient
+ // note that ConversationImpl#end() also removes the conversation from the Session
+ currentConversationContext.getConversation().end();
+ }
}
context.destroy();
webBeansContext.getBeanManagerImpl().fireEvent(payload != null ? payload : new Object(), DestroyedLiteral.INSTANCE_SESSION_SCOPED);
}
- // As the Conversations get stored inside the SessionContext we now also
- // did destroy the ConversationContext implicitly
- conversationContexts.set(null);
- conversationContexts.remove();
-
// Clear thread locals
sessionContexts.set(null);
sessionContexts.remove();
@@ -607,7 +599,7 @@ public class WebContextsService extends
return;
}
- ConversationContext context = getConversationContext(false);
+ ConversationContext context = getConversationContext(false, true);
if (context != null)
{
@@ -654,7 +646,7 @@ public class WebContextsService extends
* Get current conversation ctx.
* @return conversation context
*/
- public ConversationContext getConversationContext(boolean create)
+ public ConversationContext getConversationContext(boolean create, boolean ignoreProblems)
{
ConversationContext conversationContext = conversationContexts.get();
if (conversationContext == null && create)
@@ -662,53 +654,16 @@ public class WebContextsService extends
conversationContext = conversationManager.getConversationContext(getSessionContext(true));
conversationContexts.set(conversationContext);
- // check for busy and non-existing conversations
- String conversationId = webBeansContext.getConversationService().getConversationId();
- if (conversationId != null && conversationContext.getConversation().isTransient())
- {
- if (markAsTemporaryTransientConversation())
- {
- throw new NonexistentConversationException("Propogated conversation with cid=" + conversationId +
- " cannot be restored. It creates a new transient conversation.");
- }
- }
-
- if (conversationContext.getConversation().iUseIt() > 1)
+ if (!ignoreProblems && conversationContext.getConversation().getProblemDuringCreation() != null)
{
- if (markAsTemporaryTransientConversation())
- {
- //Throw Busy exception
- throw new BusyConversationException("Propogated conversation with cid=" + conversationId +
- " is used by other request. It creates a new transient conversation");
- }
+ throw conversationContext.getConversation().getProblemDuringCreation();
}
}
return conversationContext;
}
- /**
- * TODO probably not needed anymore
- * Remember for this request that a fresh transient conversation got created.
- * @return {@code false} if this request already got marked previously, {@code true} if we are the first to set the marker
- */
- private boolean markAsTemporaryTransientConversation()
- {
- HttpServletRequest servletRequest = requestContexts.get().getServletRequest();
- if (servletRequest != null)
- {
- String marker = (String) servletRequest.getAttribute(OWB_REQUEST_TRANSIENT_CONVERSATION_ATTRIBUTE_NAME);
- if (marker != null)
- {
- return false;
- }
-
- // if not then we need to mark it
- servletRequest.setAttribute(OWB_REQUEST_TRANSIENT_CONVERSATION_ATTRIBUTE_NAME, "true");
- }
- return true;
- }
/**
* Try to lazily start the sessionContext