001    /**
002     * Copyright 2005-2014 The Kuali Foundation
003     *
004     * Licensed under the Educational Community License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     * http://www.opensource.org/licenses/ecl2.php
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    package org.kuali.rice.krad.util;
017    
018    import org.kuali.rice.krad.UserSession;
019    import org.kuali.rice.krad.web.form.UifFormManager;
020    import org.kuali.rice.core.framework.util.ApplicationThreadLocal;
021    
022    import java.util.HashMap;
023    import java.util.LinkedList;
024    import java.util.Map;
025    import java.util.concurrent.Callable;
026    
027    /**
028     * Holds all of our thread local variables and accessors for those
029     *
030     * @author Kuali Rice Team (rice.collab@kuali.org)
031     */
032    public final class GlobalVariables {
033    
034        private static ThreadLocal<LinkedList<GlobalVariables>> GLOBAL_VARIABLES_STACK = new ApplicationThreadLocal<LinkedList<GlobalVariables>>() {
035            protected LinkedList<GlobalVariables> initialValue() {
036                LinkedList<GlobalVariables> globalVariablesStack = new LinkedList<GlobalVariables>();
037                globalVariablesStack.add(new GlobalVariables());
038                return globalVariablesStack;
039            }
040        };
041    
042        public static GlobalVariables getCurrentGlobalVariables() {
043            return GLOBAL_VARIABLES_STACK.get().getLast();
044        }
045    
046        public static void injectGlobalVariables(GlobalVariables globalVariables) {
047            GLOBAL_VARIABLES_STACK.get().add(globalVariables);
048        }
049    
050        public static GlobalVariables popGlobalVariables() {
051            return GLOBAL_VARIABLES_STACK.get().removeLast();
052        }
053    
054        static GlobalVariables pushGlobalVariables() {
055            GlobalVariables vars = new GlobalVariables();
056            GLOBAL_VARIABLES_STACK.get().add(vars);
057            return vars;
058        }
059    
060        static void reset() {
061            LinkedList<GlobalVariables> stack = GLOBAL_VARIABLES_STACK.get();
062            stack.clear();
063            stack.add(new GlobalVariables());
064        }
065    
066        private UserSession userSession = null;
067        private String hideSessionFromTestsMessage = null;
068        private MessageMap messageMap = new MessageMap();
069        private Map<String,Object> requestCache = new HashMap<String, Object>();
070        private UifFormManager uifFormManager = null;
071    
072        private GlobalVariables() {}
073    
074        /**
075         * @return the UserSession that has been assigned to this thread of execution it is important that this not be called by
076         *         anything that lives outside
077         */
078        public static UserSession getUserSession() {
079            GlobalVariables vars = getCurrentGlobalVariables();
080            String message = vars.hideSessionFromTestsMessage;
081            if (message != null) {
082                throw new RuntimeException(message);
083            }
084            return vars.userSession;
085        }
086    
087        /**
088         * Sets an error message for tests that try to use the session without declaring it.
089         * This method should be use by only KualiTestBase, not by other test code and especially not by production code.
090         *
091         * @param message the detail to throw, or null to allow access to the session
092         */
093        public static void setHideSessionFromTestsMessage(String message) {
094            GlobalVariables vars = getCurrentGlobalVariables();
095            vars.hideSessionFromTestsMessage = message;
096        }
097    
098        /**
099         * sets the userSession object into the global variable for this thread
100         *
101         * @param userSession
102         */
103        public static void setUserSession(UserSession userSession) {
104            GlobalVariables vars = getCurrentGlobalVariables();
105            vars.userSession = userSession;
106        }
107    
108        public static MessageMap getMessageMap() {
109            GlobalVariables vars = getCurrentGlobalVariables();
110            return vars.messageMap;
111        }
112    
113        /**
114         * Merges a message map into the global variables error map
115         * @param messageMap
116         */
117        public static void mergeErrorMap(MessageMap messageMap) {
118            getMessageMap().getErrorMessages().putAll(messageMap.getErrorMessages());
119            getMessageMap().getWarningMessages().putAll(messageMap.getWarningMessages());
120            getMessageMap().getInfoMessages().putAll(messageMap.getInfoMessages());
121        }
122    
123        /**
124         * Sets a new (clean) MessageMap
125         *
126         * @param messageMap
127         */
128        public static void setMessageMap(MessageMap messageMap) {
129            GlobalVariables vars = getCurrentGlobalVariables();
130            vars.messageMap = messageMap;
131        }
132    
133        public static Object getRequestCache(String cacheName) {
134            GlobalVariables vars = getCurrentGlobalVariables();
135            return vars.requestCache.get(cacheName);
136        }
137    
138        public static void setRequestCache(String cacheName, Object cacheObject) {
139            GlobalVariables vars = getCurrentGlobalVariables();
140            synchronized (vars.requestCache) {
141                vars.requestCache.put(cacheName, cacheObject);
142            }
143        }
144    
145        /**
146         * Retrieves the {@link org.kuali.rice.krad.web.form.UifFormManager} which can be used to store and remove forms
147         * from the session
148         *
149         * @return UifFormManager
150         */
151        public static UifFormManager getUifFormManager() {
152            GlobalVariables vars = getCurrentGlobalVariables();
153            return vars.uifFormManager;
154        }
155    
156        /**
157         * Sets a {@link org.kuali.rice.krad.web.form.UifFormManager} for the current thread
158         *
159         * @param uifFormManager
160         */
161        public static void setUifFormManager(UifFormManager uifFormManager) {
162            GlobalVariables vars = getCurrentGlobalVariables();
163            vars.uifFormManager = uifFormManager;
164        }
165    
166        /**
167         * Clears out GlobalVariable objects with the exception of the UserSession
168         */
169        public static void clear() {
170            GlobalVariables vars = getCurrentGlobalVariables();
171            vars.messageMap = new MessageMap();
172            vars.requestCache = new HashMap<String,Object>();
173        }
174    
175        /**
176         * Pushes a new GlobalVariables object onto the ThreadLocal GlobalVariables stack, invokes the runnable,
177         * and pops the GlobalVariables off in a finally clause
178         * 
179         * @param <T> callable return type
180         * @param callable the code to run under a new set of GlobalVariables
181         * @return return value from callable
182         * @throws Exception from {@link Callable#call()}
183         */
184        public static <T> T doInNewGlobalVariables(Callable<T> callable) throws Exception {
185            return doInNewGlobalVariables(null, callable);
186        }
187    
188        /**
189         * Convenience method that creates a new GlobalVariables stack frame, initialized with the provided
190         * UserSession (which may be the previous UserSession).
191         *
192         * @param <T> callable return type
193         * @param userSession the UserSession to initialize the new frame with (may be null)
194         * @param callable the code to run under a new set of GlobalVariables
195         * @return return value from callable
196         * @throws Exception from {@link Callable#call()}
197         */
198        public static <T> T doInNewGlobalVariables(UserSession userSession, Callable<T> callable) throws Exception {
199            try {
200                GlobalVariables vars = pushGlobalVariables();
201                if (userSession != null) {
202                    vars.userSession = userSession;
203                }
204                return callable.call();
205            } finally {
206                popGlobalVariables();
207            }
208        }
209    }