Class ContextService


  • public final class ContextService
    extends java.lang.Object
    A set of static methods to supply easier access to contexts.
    • Field Detail

      • threadContextList

        private java.lang.ThreadLocal<java.lang.Object> threadContextList
        Maintains a list of all the contexts that this thread has created and/or used. The object stored in the thread local varys according how this thread has been used and will be one of:
        • null - the thread no affiliation with a context manager.
        • ContextManager - the current thread has used or is using this context manager. If ContextManager.activeThread equals the current thread then the thread is currently active with the ContextManager. In this case ContextManager.activeCount will be greater than zero and represent the level of nested setCurrentContextmanager calls. If ContextManager.activeThread is null then no other thread is using the Contextmanager, if ContextManager.activeThread is not-null and not equal to the current thread then some other thread is using the context. It is assumed that only a single thread can be using a ContextManager at any time and this is enforced by synchronization outside the ContextManager. E.g for JDBC connections, synchronization at the JDBC level.
        • ContextManagerStack containing ContextManagers - the current thread is actively using multiple different ContextManagers, with nesting. All ContextManagers in the stack will have activeThread set to the current thread, and their activeCount set to -1. This is because nesting is solely represented by the stack, with the current context manager on top of the stack. This supports multiple levels of nesting across two stacks, e.g. C1->C2->C2->C1->C2.
        This thread local is used to find the current context manager. Basically it provides fast access to a list of candidate contexts. If one of the contexts has its activeThread equal to the current thread then it is the current context manager. If the thread has pushed multiple contexts (e.g. open a new non-nested Derby connection from a server side method) then threadContextList will contain a Stack. The value for each cm will be a push order, with higher numbers being more recently pushed. To support the case where a single context manager is pushed twice (nested connection), the context manager keeps track of the number of times it has been pushed (set). Note that our synchronization requires that a single context can only be accessed by a single thread at a time. In the JDBC layer this is enforced by the synchronization on the connection object.

        There are two cases we are trying to optimise.

        • Typical JDBC client program where there a Connection is always executed using a single thread. In this case this variable will contain the Connection's context manager
        • Typical application server pooled connection where a single thread may use a connection from a pool for the lifetime of the request. In this case this variable will contain a WeakReference.

        Single thread for Connection execution.
                threadContextList.get() == cm
                // while in JDBC engine code
                cm.activeThread == Thread.currentThread();
                cm.activeCount = 1;
                

        J2EE single thread for lifetime of execution.
                // thread executing request
                 threadContextList.get() == cm
                // while in JDBC engine code
                cm.activeThread == Thread.currentThread();
                cm.activeCount = 1;
                
                // other threads that have recently executed
                // the same connection can have
                threadContextList.get() == cm
                cm.activeThread != Thread.currentThread();
               

        Nested routine calls within single connection
                threadContextList.get() == cm
                // Within server-side JDBC code in a
                // function called from another function/procedure
                // called from an applications's statement
                // (three levels of nesting)
                cm.activeThread == Thread.currentThread();
                cm.activeCount = 3;         
                

        Nested routine calls with the inner routine using a different connection to access a Derby database. Note nesting of orignal Contextmanager cm is changed from an activeCount of 2 to nesting within the stack once multiple ContextManagers are involved.
                threadContextList.get() == stack {cm2,cm,cm}
                cm.activeThread == Thread.currentThread();
                cm.activeCount = -1; // nesting in stack
                cm2.activeThread == Thread.currentThread();
                cm2.activeCount = -1; // nesting in stack
                

        Nested multiple ContextManagers, the code supports this, though it may not be possible currently to have a stack like this from SQL/JDBC.
                threadContextList.get() == stack {cm3,cm2,cm,cm2,cm,cm}
                cm.activeThread == Thread.currentThread();
                cm.activeCount = -1; // nesting in stack
                cm2.activeThread == Thread.currentThread();
                cm2.activeCount = -1; // nesting in stack
                cm3.activeThread == Thread.currentThread();
                cm3.activeCount = -1; // nesting in stack
                
    • Constructor Detail

      • ContextService

        public ContextService()
        Create a new ContextService for a Derby system. Only a single system is active at any time.
    • Method Detail

      • stop

        public static void stop()
        So it can be given to us and taken away...
      • getContext

        public static Context getContext​(java.lang.String contextId)
        Find the context with the given name in the context service factory loaded for the system.
        Returns:
        The requested context, null if it doesn't exist.
      • getContextOrNull

        public static Context getContextOrNull​(java.lang.String contextId)
        Find the context with the given name in the context service factory loaded for the system. This version will not do any debug checking, but return null quietly if it runs into any problems.
        Returns:
        The requested context, null if it doesn't exist.
      • getCurrentContextManager

        public ContextManager getCurrentContextManager()
        Get current Context Manager linked to the current Thread. See setCurrentContextManager for details. Note that this call can be expensive and is only intended to be used in "stateless" situations. Ideally code has a reference to the correct ContextManager from another Object, such as a pushed Context.
        Returns:
        ContextManager current Context Manager
      • resetCurrentContextManager

        public void resetCurrentContextManager​(ContextManager cm)
        Break the link between the current Thread and the passed in ContextManager. Called in a pair with setCurrentContextManager, see that method for details.
      • addToThreadList

        private boolean addToThreadList​(java.lang.Thread me,
                                        ContextManager associateCM)
        The current thread (passed in a me) is setting associateCM to be its current context manager. Sets the thread local variable threadContextList to reflect associateCM being the current ContextManager.
        Returns:
        True if the nesting level is to be represented in the ContextManager.activeCount field. False if not.
        See Also:
        ContextManager.activeCount, ContextManager.activeThread
      • setCurrentContextManager

        public void setCurrentContextManager​(ContextManager cm)
        Link the current thread to the passed in Contextmanager so that a subsequent call to getCurrentContextManager by the current Thread will return cm. ContextManagers are tied to a Thread while the thread is executing Derby code. For example on most JDBC method calls the ContextManager backing the Connection object is tied to the current Thread at the start of the method and reset at the end of the method. Once the Thread has completed its Derby work the method resetCurrentContextManager must be called with the same ContextManager to break the link. Note that a subsquent use of the ContextManager may be on a separate Thread, the Thread is only linked to the ContextManager between the setCurrentContextManager and resetCurrentContextManager calls.
        ContextService supports nesting of calls by a single Thread, either with the same ContextManager or a different ContextManager.
        • The same ContextManager would be pushed during a nested JDBC call in a procedure or function.
        • A different ContextManager would be pushed during a call on a different embedded JDBC Connection in a procedure or function.
      • newContextManager

        public ContextManager newContextManager()
        It's up to the caller to track this context manager and set it in the context manager list using setCurrentContextManager. We don't keep track of it due to this call being made.
      • notifyAllActiveThreads

        public void notifyAllActiveThreads​(Context c)
      • removeContext

        void removeContext​(ContextManager cm)
        Remove a ContextManager from the list of all active contexts managers.