View Javadoc

1   /*
2    *   Copyright 2004 The Apache Software Foundation
3    *
4    *   Licensed under the Apache License, Version 2.0 (the "License");
5    *   you may not use this file except in compliance with the License.
6    *   You may obtain a copy of the License at
7    *
8    *       http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *   Unless required by applicable law or agreed to in writing, software
11   *   distributed under the License is distributed on an "AS IS" BASIS,
12   *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *   See the License for the specific language governing permissions and
14   *   limitations under the License.
15   *
16   */
17  package org.apache.ldap.server.invocation;
18  
19  
20  import java.util.ArrayList;
21  import java.util.IdentityHashMap;
22  import java.util.List;
23  import java.util.Map;
24  
25  import javax.naming.Context;
26  
27  
28  /***
29   * Keeps track of recursive {@link Invocation}s.  This stack assumes an invocation
30   * occurs in the same thread since it is called first, so we manages stacks
31   * for each invocation in {@link ThreadLocal}-like manner.  You can just use
32   * {@link #getInstance()} to get current invocation stack.
33   * <p>
34   * Using {@link InvocationStack}, you can find out current effective JNDI
35   * {@link Context} or detect infinite recursions.
36   * 
37   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
38   * @version $Rev: 264732 $, $Date: 2005-08-30 04:04:51 -0400 (Tue, 30 Aug 2005) $
39   */
40  public final class InvocationStack
41  {
42      // I didn't use ThreadLocal to release contexts explicitly.
43      // It seems like JDK 1.5 supports explicit release by introducing
44      // <tt>ThreadLocal.remove()</tt>, but we're still targetting 1.4.
45      private static final Map stacks = new IdentityHashMap();
46      
47      /***
48       * Returns the invocation stack of current thread.
49       */
50      public static InvocationStack getInstance()
51      {
52          Thread currentThread = Thread.currentThread();
53          InvocationStack ctx;
54          synchronized( stacks )
55          {
56              ctx = ( InvocationStack ) stacks.get( currentThread );
57              if( ctx == null )
58              {
59                  ctx = new InvocationStack();
60              }
61          }
62          return ctx;
63      }
64  
65      private final Thread thread;
66      private final List stack = new ArrayList();
67  
68      private InvocationStack()
69      {
70          Thread currentThread = Thread.currentThread();
71          this.thread = currentThread;
72          // This operation is already synchronized from getInstance()
73          stacks.put( currentThread, this );
74      }
75      
76      /***
77       * Returns an array of {@link Invocation}s.  0th element is the
78       * latest invocation.
79       */
80      public Invocation[] toArray()
81      {
82          Invocation[] result = new Invocation[ stack.size() ];
83          result = ( Invocation[] ) stack.toArray( result );
84          return result;
85      }
86      
87      /***
88       * Returns the latest invocation.
89       */
90      public Invocation peek()
91      {
92          return ( Invocation ) this.stack.get( 0 );
93      }
94      
95      /***
96       * Pushes the specified invocation to this stack.
97       */
98      public void push( Invocation invocation )
99      {
100         this.stack.add( 0, invocation );
101     }
102     
103     /***
104      * Pops the latest invocation from this stack.  This stack is released
105      * automatically if you pop all items from this stack.
106      */
107     public Invocation pop()
108     {
109         Invocation invocation = ( Invocation ) this.stack.remove( 0 );
110         if( this.stack.size() == 0 )
111         {
112             synchronized( stacks )
113             {
114                 stacks.remove( thread );
115             }
116         }
117 
118         return invocation;
119     }
120 }