/*
 * JBoss, Home of Professional Open Source
 * Copyright 2010, Red Hat, Inc. and/or its affiliates, and individual
 * contributors by the @authors tag. See the copyright.txt in the
 * distribution for a full listing of individual contributors.
 *
 * 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.jboss.weld.bean.proxy;

import java.util.EmptyStackException;
import java.util.HashSet;
import java.util.Set;
import java.util.Stack;

/**
 * A class that holds the interception (and decoration) contexts which are currently in progress.
 *
 * An interception context is a set of {@link CombinedInterceptorAndDecoratorStackMethodHandler} references for which interception is currently
 * suppressed (so that self-invocation is not possible).
 * Such references are added as soon as a CombinedMethodHandler is executed in an interception context that
 * does not hold it.
 *
 * Classes may create new interception contexts as necessary (e.g. allowing client proxies to create new interception
 * contexts in order to make circular references interceptable multiple times).
 *
 * @author Marius Bogoevici
 */
public class InterceptionDecorationContext
{
   private static ThreadLocal<Stack<Set<CombinedInterceptorAndDecoratorStackMethodHandler>>> interceptionContexts = new ThreadLocal<Stack<Set<CombinedInterceptorAndDecoratorStackMethodHandler>>>();
   
   public static Set<CombinedInterceptorAndDecoratorStackMethodHandler> pop()
   {
      Stack<Set<CombinedInterceptorAndDecoratorStackMethodHandler>> stack = interceptionContexts.get();
      if (stack == null)
      {
         throw new EmptyStackException();
      }
      else
      {
         try
         {
            return stack.pop();
         }
         finally
         {
            if (stack.isEmpty())
            {
               interceptionContexts.remove();
            }
         }
      }
   }
   
   public static Set<CombinedInterceptorAndDecoratorStackMethodHandler> push(Set<CombinedInterceptorAndDecoratorStackMethodHandler> item)
   {
      Stack<Set<CombinedInterceptorAndDecoratorStackMethodHandler>> stack = interceptionContexts.get();
      if (stack == null)
      {
         stack = new Stack<Set<CombinedInterceptorAndDecoratorStackMethodHandler>>();
         interceptionContexts.set(stack);
      }
      stack.push(item);
      return item;
   }
   
   public static Set<CombinedInterceptorAndDecoratorStackMethodHandler> peek()
   {
      Stack<Set<CombinedInterceptorAndDecoratorStackMethodHandler>> stack = interceptionContexts.get();
      if (stack == null)
      {
         throw new EmptyStackException();
      }
      else
      {
         return stack.peek();
      }
   }
   
   public static boolean empty()
   {
      Stack<Set<CombinedInterceptorAndDecoratorStackMethodHandler>> stack = interceptionContexts.get();
      if (stack == null)
      {
         return true;
      }
      else
      {
         return stack.empty();
      }
   }
   

   public static void endInterceptorContext()
   {
      pop();
   }

   public static void startInterceptorContext()
   {
      push(new HashSet<CombinedInterceptorAndDecoratorStackMethodHandler>());
   }
}

@@ -828,16 +828,44 @@
 proxy;%0A%0A
+import java.util.ArrayList;%0A
 import j
@@ -959,21 +959,20 @@
 va.util.
-Stack
+List
 ;%0A%0A/**%0A 
@@ -1704,37 +1704,36 @@
 tic ThreadLocal%3C
-Stack
+List
 %3CSet%3CCombinedInt
@@ -1813,21 +1813,20 @@
 adLocal%3C
-Stack
+List
 %3CSet%3CCom
@@ -1878,37 +1878,38 @@
 r%3E%3E%3E();%0A   %0A   p
-ublic
+rivate
  static Set%3CComb
@@ -1964,37 +1964,36 @@
 op()%0A   %7B%0A      
-Stack
+List
 %3CSet%3CCombinedInt
@@ -2220,20 +2220,39 @@
 n stack.
-pop(
+remove(stack.size() - 1
 );%0A     
@@ -2416,37 +2416,38 @@
  %7D%0A   %7D%0A   %0A   p
-ublic
+rivate
  static Set%3CComb
@@ -2562,37 +2562,36 @@
 tem)%0A   %7B%0A      
-Stack
+List
 %3CSet%3CCombinedInt
@@ -2721,21 +2721,25 @@
 k = new 
-Stack
+ArrayList
 %3CSet%3CCom
@@ -2852,20 +2852,19 @@
   stack.
-push
+add
 (item);%0A
@@ -2973,37 +2973,36 @@
 ek()%0A   %7B%0A      
-Stack
+List
 %3CSet%3CCombinedInt
@@ -3193,27 +3193,324 @@
     
-return stack.peek()
+int last = stack.size() - 1;%0A         Set%3CCombinedInterceptorAndDecoratorStackMethodHandler%3E result = stack.get(last);%0A         if (result == null)%0A         %7B%0A            result = new HashSet%3CCombinedInterceptorAndDecoratorStackMethodHandler%3E();%0A            stack.set(last, result);%0A         %7D%0A         return result
 ;%0A  
@@ -3568,21 +3568,20 @@
 %7B%0A      
-Stack
+List
 %3CSet%3CCom
@@ -3769,17 +3769,19 @@
 n stack.
-e
+isE
 mpty();%0A
@@ -3937,71 +3937,11 @@
 sh(n
-ew HashSet%3CCombinedInterceptorAndDecoratorStackMethodHandler%3E()
+ull
 );%0A 

Use ArrayList instead of Stack to avoid synchronization, lazily initialize the set only when required