package org.hotswap.agent.plugin.owb.command;
import java.util.ArrayList;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
import org.apache.webbeans.context.ConversationContext;
import org.apache.webbeans.context.SessionContext;
import org.apache.webbeans.web.context.ServletRequestContext;
/**
* The Class WebContextsTracker.
*
* @author Vladimir Dvorak
*/
public class WebContextsTracker implements Iterable {
public static class WebContextsSet {
public final ServletRequestContext requestContext;
public final ConversationContext conversationContext;
public final SessionContext sessionContext;
public WebContextsSet(ServletRequestContext requestContext, ConversationContext conversationContext, SessionContext sessionContext) {
this.requestContext = requestContext;
this.conversationContext = conversationContext;
this.sessionContext = sessionContext;
}
}
public class WebContextsSetIterator implements Iterator {
private int index = 0;
private List<WebContextsSet> wcsList;
public WebContextsSetIterator(List wcsList) {
this.wcsList = wcsList;
}
@Override
public boolean hasNext() {
return index < wcsList.size();
}
@Override
public Object next() {
if (index < wcsList.size()) {
setWebContextsSet(wcsList.get(index));
index++;
}
return null;
}
@Override
public void remove() {
}
}
private Map<ServletRequestContext, SessionContext> request2SessionMap = new WeakHashMap<>();
private Map<ServletRequestContext, ConversationContext> request2ConversationMap = new WeakHashMap<>();
private Map<ConversationContext, SessionContext> conversation2SessionMap = new WeakHashMap<>();
private Map<ServletRequestContext, Boolean> requestMap = new WeakHashMap<>();
private Map<SessionContext, Boolean> sessionMap = new WeakHashMap<>();
public ThreadLocalSessionContextSubscriber sessionContexts = new ThreadLocalSessionContextSubscriber();
public ThreadLocalConversationContextSubscriber conversationContexts = new ThreadLocalConversationContextSubscriber();
public ThreadLocalRequestContextSubscriber requestContexts = new ThreadLocalRequestContextSubscriber();
private class ThreadLocalSessionContextSubscriber extends ThreadLocal<SessionContext> {
@Override
public void set(SessionContext value) {
if (value == null) {
if (super.get() != null) {
sessionMap.remove(super.get());
}
} else {
sessionMap.put(value, true);
if (requestContexts.get() != null) {
request2SessionMap.put(requestContexts.get(), value);
}
if (conversationContexts.get() != null) {
conversation2SessionMap.put(conversationContexts.get(), value);
}
}
super.set(value);
}
public void superSet(SessionContext value) {
super.set(value);
}
}
private class ThreadLocalConversationContextSubscriber extends ThreadLocal<ConversationContext> {
@Override
public void set(ConversationContext value) {
if (value == null) {
if (super.get() != null) {
conversation2SessionMap.remove(super.get());
}
} else {
if (sessionContexts.get() != null) {
conversation2SessionMap.put(value, sessionContexts.get());
}
if (requestContexts.get() != null) {
request2ConversationMap.put(requestContexts.get(), value);
}
}
super.set(value);
}
public void superSet(ConversationContext value) {
super.set(value);
}
}
private class ThreadLocalRequestContextSubscriber extends ThreadLocal<ServletRequestContext> {
@Override
public void set(ServletRequestContext value) {
if (value == null) {
if (super.get() != null) {
requestMap.remove(super.get());
request2SessionMap.remove(super.get());
}
} else {
requestMap.put(value, true);
if (sessionContexts.get() != null) {
request2SessionMap.put(value, sessionContexts.get());
}
}
super.set(value);
}
public void superSet(ServletRequestContext value) {
super.set(value);
}
}
@Override
public Iterator iterator() {
List<WebContextsSet> wcsList = new ArrayList<>();
Map<ConversationContext, Boolean> foundConversationContexts = new IdentityHashMap<>();
Map<SessionContext, Boolean> foundSessionContexts = new IdentityHashMap<>();
// 1. iterate over request->session map and join conversation
for (Map.Entry<ServletRequestContext, SessionContext> entry: request2SessionMap.entrySet()) {
WebContextsSet wcc = createWebContextSet(entry.getKey(), request2ConversationMap.get(entry.getKey()), entry.getValue());
if (wcc != null) {
wcsList.add(wcc);
if (wcc.conversationContext != null) {
foundConversationContexts.put(wcc.conversationContext, true);
}
if (wcc.sessionContext != null) {
foundSessionContexts.put(wcc.sessionContext, true);
}
}
}
// 2. iterate over conversation->session map and use only not found conversations in step (1)
for (Map.Entry<ConversationContext, SessionContext> entry: conversation2SessionMap.entrySet()) {
if (!foundConversationContexts.containsKey(entry.getKey())) {
WebContextsSet wcc = createWebContextSet(null, entry.getKey(), entry.getValue());
if (wcc != null) {
wcsList.add(wcc);
if (wcc.sessionContext != null) {
foundSessionContexts.put(wcc.sessionContext, true);
}
}
}
}
// 3. iterate over session map and use only not found sessions in step (1-2)
for (Map.Entry<SessionContext, Boolean> entry: sessionMap.entrySet()) {
if (!foundSessionContexts.containsKey(entry.getKey())) {
WebContextsSet wcc = createWebContextSet(null, null, entry.getKey());
if (wcc != null) {
wcsList.add(wcc);
}
}
}
// 4. for completeness use all standalone requests
for (Map.Entry<ServletRequestContext, Boolean> entry: requestMap.entrySet()) {
if (!request2SessionMap.containsKey(entry.getKey())) {
WebContextsSet wcc = createWebContextSet(entry.getKey(), null, null);
if (wcc != null) {
wcsList.add(wcc);
}
}
}
return new WebContextsSetIterator(wcsList);
}
private WebContextsSet createWebContextSet(ServletRequestContext requestContext,
ConversationContext conversationContext, SessionContext sessionContext) {
if (requestContext == null && conversationContext == null && sessionContext == null) {
return null;
}
if (requestContext != null && !requestContext.isActive() ||
conversationContext != null && !conversationContext.isActive() ||
sessionContext != null && !sessionContext.isActive()) {
return null;
}
return new WebContextsSet(requestContext, conversationContext, sessionContext);
}
public void setWebContextsSet(WebContextsSet wcc) {
((ThreadLocalRequestContextSubscriber)requestContexts).superSet(wcc.requestContext);
((ThreadLocalConversationContextSubscriber)conversationContexts).superSet(wcc.conversationContext);
((ThreadLocalSessionContextSubscriber)sessionContexts).superSet(wcc.sessionContext);
}
}