001/**
002 * Copyright 2005-2016 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 */
016package org.kuali.rice.krad.util;
017
018import org.kuali.rice.krad.UserSession;
019import org.kuali.rice.krad.uif.util.UifFormManager;
020import org.kuali.rice.core.framework.util.ApplicationThreadLocal;
021
022import java.util.HashMap;
023import java.util.LinkedList;
024import java.util.Map;
025import 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 */
032public 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    private static GlobalVariables getCurrentGlobalVariables() {
043        return GLOBAL_VARIABLES_STACK.get().getLast();
044    }
045
046    static GlobalVariables pushGlobalVariables() {
047        GlobalVariables vars = new GlobalVariables();
048        GLOBAL_VARIABLES_STACK.get().add(vars);
049        return vars;
050    }
051
052    static GlobalVariables popGlobalVariables() {
053        return GLOBAL_VARIABLES_STACK.get().removeLast();
054    }
055
056    static void reset() {
057        LinkedList<GlobalVariables> stack = GLOBAL_VARIABLES_STACK.get();
058        stack.clear();
059        stack.add(new GlobalVariables());
060    }
061
062    private UserSession userSession = null;
063    private String hideSessionFromTestsMessage = null;
064    private MessageMap messageMap = new MessageMap();
065    private Map<String,Object> requestCache = new HashMap<String, Object>();
066    private UifFormManager uifFormManager = null;
067
068    private GlobalVariables() {}
069
070    /**
071     * @return the UserSession that has been assigned to this thread of execution it is important that this not be called by
072     *         anything that lives outside
073     */
074    public static UserSession getUserSession() {
075        GlobalVariables vars = getCurrentGlobalVariables();
076        String message = vars.hideSessionFromTestsMessage;
077        if (message != null) {
078            throw new RuntimeException(message);
079        }
080        return vars.userSession;
081    }
082
083    /**
084     * Sets an error message for tests that try to use the session without declaring it.
085     * This method should be use by only KualiTestBase, not by other test code and especially not by production code.
086     *
087     * @param message the detail to throw, or null to allow access to the session
088     */
089    public static void setHideSessionFromTestsMessage(String message) {
090        GlobalVariables vars = getCurrentGlobalVariables();
091        vars.hideSessionFromTestsMessage = message;
092    }
093
094    /**
095     * sets the userSession object into the global variable for this thread
096     *
097     * @param userSession
098     */
099    public static void setUserSession(UserSession userSession) {
100        GlobalVariables vars = getCurrentGlobalVariables();
101        vars.userSession = userSession;
102    }
103
104    public static MessageMap getMessageMap() {
105        GlobalVariables vars = getCurrentGlobalVariables();
106        return vars.messageMap;
107    }
108
109    /**
110     * Merges a message map into the global variables error map
111     * @param messageMap
112     */
113    public static void mergeErrorMap(MessageMap messageMap) {
114        getMessageMap().getErrorMessages().putAll(messageMap.getErrorMessages());
115        getMessageMap().getWarningMessages().putAll(messageMap.getWarningMessages());
116        getMessageMap().getInfoMessages().putAll(messageMap.getInfoMessages());
117    }
118
119    /**
120     * Sets a new (clean) MessageMap
121     *
122     * @param messageMap
123     */
124    public static void setMessageMap(MessageMap messageMap) {
125        GlobalVariables vars = getCurrentGlobalVariables();
126        vars.messageMap = messageMap;
127    }
128
129    public static Object getRequestCache(String cacheName) {
130        GlobalVariables vars = getCurrentGlobalVariables();
131        return vars.requestCache.get(cacheName);
132    }
133
134    public static void setRequestCache(String cacheName, Object cacheObject) {
135        GlobalVariables vars = getCurrentGlobalVariables();
136        vars.requestCache.put(cacheName, cacheObject);
137    }
138
139    /**
140     * Retrieves the {@link org.kuali.rice.krad.uif.util.UifFormManager} which can be used to store and remove forms
141     * from the session
142     *
143     * @return UifFormManager
144     */
145    public static UifFormManager getUifFormManager() {
146        GlobalVariables vars = getCurrentGlobalVariables();
147        return vars.uifFormManager;
148    }
149
150    /**
151     * Sets a {@link org.kuali.rice.krad.uif.util.UifFormManager} for the current thread
152     *
153     * @param uifFormManager
154     */
155    public static void setUifFormManager(UifFormManager uifFormManager) {
156        GlobalVariables vars = getCurrentGlobalVariables();
157        vars.uifFormManager = uifFormManager;
158    }
159
160    /**
161     * Clears out GlobalVariable objects with the exception of the UserSession
162     */
163    public static void clear() {
164        GlobalVariables vars = getCurrentGlobalVariables();
165        vars.messageMap = new MessageMap();
166        vars.requestCache = new HashMap<String,Object>();
167    }
168
169    /**
170     * Pushes a new GlobalVariables object onto the ThreadLocal GlobalVariables stack, invokes the runnable,
171     * and pops the GlobalVariables off in a finally clause
172     * @param callable the code to run under a new set of GlobalVariables
173     */
174    public static <T> T doInNewGlobalVariables(Callable<T> callable) throws Exception {
175        return doInNewGlobalVariables(null, callable);
176    }
177
178    /**
179     * Convenience method that creates a new GlobalVariables stack frame, initialized with the provided
180     * UserSession (which may be the previous UserSession).
181     * @param userSession the UserSession to initialize the new frame with (may be null)
182     * @param callable the code to run under a new set of GlobalVariables
183     * @throws Exception
184     */
185    public static <T> T doInNewGlobalVariables(UserSession userSession, Callable<T> callable) throws Exception {
186        try {
187            GlobalVariables vars = pushGlobalVariables();
188            if (userSession != null) {
189                vars.userSession = userSession;
190            }
191            return callable.call();
192        } finally {
193            popGlobalVariables();
194        }
195    }
196}