001 /** 002 * Copyright 2010 The Kuali Foundation Licensed under the 003 * Educational Community License, Version 2.0 (the "License"); you may 004 * not use this file except in compliance with the License. You may 005 * obtain a copy of the License at 006 * 007 * http://www.osedu.org/licenses/ECL-2.0 008 * 009 * Unless required by applicable law or agreed to in writing, 010 * software distributed under the License is distributed on an "AS IS" 011 * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 012 * or implied. See the License for the specific language governing 013 * permissions and limitations under the License. 014 */ 015 016 package org.kuali.student.common.ui.client.application; 017 018 import java.util.ArrayList; 019 import java.util.HashMap; 020 import java.util.HashSet; 021 import java.util.Iterator; 022 import java.util.List; 023 import java.util.Map; 024 import java.util.Map.Entry; 025 026 import org.kuali.student.common.messages.dto.Message; 027 import org.kuali.student.common.ui.client.configurable.mvc.FieldDescriptor; 028 import org.kuali.student.common.ui.client.mvc.HasCrossConstraints; 029 import org.kuali.student.common.ui.client.security.SecurityContext; 030 import org.kuali.student.common.ui.client.service.ServerPropertiesRpcService; 031 import org.kuali.student.common.ui.client.service.ServerPropertiesRpcServiceAsync; 032 033 import com.google.gwt.core.client.GWT; 034 import com.google.gwt.user.client.rpc.AsyncCallback; 035 036 /** 037 * The application contains information about who is currently logged in, the security context, and access 038 * to messages loaded from the message service in the app. It provides and a static way to obtain this 039 * information across the entire app. 040 * 041 * @author Kuali Student 042 * 043 */ 044 public class ApplicationContext { 045 private ServerPropertiesRpcServiceAsync serverPropertiesRpcService = GWT.create(ServerPropertiesRpcService.class); 046 047 private boolean loggedIn = true; 048 private String userId = "testuser"; 049 private String version = "KS"; 050 private List<String> roles = new ArrayList<String>(); 051 052 private Map<String, Map<String, String>> messages = new HashMap<String, Map<String,String>>(); 053 private Map<String, String> flatMessages = new HashMap<String, String>(); 054 private List<Message> messagesList = new ArrayList<Message>(); 055 056 private SecurityContext securityContext; 057 private String applicationContextUrl; 058 059 //These maps are used to store query paths to their corresponding fieldDefinitions, and also whcih fields have cross constraints 060 private String parentPath = ""; 061 private HashMap<String,HashMap<String,FieldDescriptor>> pathToFieldMapping = new HashMap<String,HashMap<String,FieldDescriptor>>(); 062 private HashMap<String,HashMap<String,HashSet<HasCrossConstraints>>> crossConstraints = new HashMap<String,HashMap<String,HashSet<HasCrossConstraints>>>(); 063 // private HashMap<String,HashMap<FieldDescriptor, String>> defaultValueMapping = new HashMap<String,HashMap<FieldDescriptor, String>>(); 064 /** 065 * This constructor should only be visible to the common application package. If ApplicationContext is 066 * required outside this package do Application.getApplicationContext(); 067 */ 068 protected ApplicationContext() { 069 roles.add("role1"); 070 roles.add("role2"); 071 072 serverPropertiesRpcService.getContextPath(new AsyncCallback<String>(){ 073 074 @Override 075 public void onFailure(Throwable caught) { 076 throw new RuntimeException("Fatal - Unable to initialze application context"); 077 } 078 079 @Override 080 public void onSuccess(String result) { 081 applicationContextUrl = result; 082 } 083 }); 084 } 085 086 public void setLoggedIn(boolean loggedIn) { 087 this.loggedIn = loggedIn; 088 } 089 090 public void setUserId(String userId) { 091 this.userId = userId; 092 } 093 094 public void setRoles(List<String> roles) { 095 this.roles = roles; 096 } 097 098 public boolean isLoggedIn() { 099 return loggedIn; 100 } 101 102 public String getUserId() { 103 return userId; 104 } 105 106 public List<String> getRoles() { 107 return roles; 108 } 109 110 /** 111 * Adds the messages in the list of messages to the map of the messages 112 * @param messages 113 */ 114 public void addMessages(List<Message> messages) { 115 messagesList.addAll(messages); 116 for (Message m : messages) { 117 String groupName = m.getGroupName(); 118 Map<String, String> group = this.messages.get(groupName); 119 if (group == null) { 120 group = new HashMap<String, String>(); 121 this.messages.put(groupName, group); 122 } 123 group.put(m.getId(), m.getValue()); 124 flatMessages.put(m.getId(), m.getValue()); 125 } 126 } 127 128 /** 129 * Get a message by a unique id 130 */ 131 public String getMessage(String messageId) { 132 return flatMessages.get(messageId); 133 } 134 135 /** 136 * Returns all the messages in the ApplicationContext 137 */ 138 public List<Message> getMessages() { 139 return messagesList; 140 } 141 142 143 /** 144 * Get message by the group it is in and its unique id within that group 145 */ 146 public String getMessage(String groupName, String messageId) { 147 148 String result = null; 149 150 Map<String, String> group = this.messages.get(groupName); 151 if (group != null) { 152 result = group.get(messageId); 153 } 154 155 return result; 156 } 157 158 /** 159 * 160 * This method looks up a UI Label in the messages cache. 161 * First looks for a label specific to the type and state of the field. 162 * If none found try for a generalized label. 163 * Otherwise return the supplied fieldId 164 * Groups provide namespace for same label ids within different LUs 165 * 166 * @param groupName - for example 'course' or 'program' 167 * @param type 168 * @param state 169 * @param fieldId 170 * @return 171 */ 172 public String getUILabel(String groupName, String type, String state, String fieldId) { 173 174 String label = getMessage(groupName, type + ":" + state + ":" + fieldId); 175 176 if (label == null) 177 label = getMessage(groupName, fieldId); 178 179 if (label == null) 180 label = fieldId; 181 182 return label; 183 184 } 185 186 /** 187 * Same as getUILabel(String groupName, String type, String state, String fieldId) with no 188 * type and state needed 189 */ 190 public String getUILabel(String groupName, String fieldId) { 191 192 String label = getMessage(groupName, fieldId); 193 194 if (label == null) 195 label = fieldId; 196 197 return label; 198 199 } 200 201 /** 202 * Get the security context for the app 203 * @return SecurityContext 204 */ 205 public SecurityContext getSecurityContext() { 206 return securityContext; 207 } 208 209 public void setSecurityContext(SecurityContext securityContext) { 210 this.securityContext = securityContext; 211 } 212 213 /** 214 * Application URL based on the serverPropertiesRPC service result 215 */ 216 public String getApplicationContextUrl() { 217 return applicationContextUrl; 218 } 219 220 public void setVersion(String version) { 221 this.version = version; 222 } 223 224 public String getVersion() { 225 return version; 226 } 227 228 /** 229 * Adds a mapping from path to a list of field descriptors for a given namespace 230 * namespace defaults to _default if null 231 * @param path 232 * @param fd 233 */ 234 public void putCrossConstraint(String namespace, String path, HasCrossConstraints fd){ 235 if(namespace==null){ 236 namespace="_default"; 237 } 238 239 HashMap<String,HashSet<HasCrossConstraints>> crossConstraintMap = crossConstraints.get(namespace); 240 if(crossConstraintMap==null){ 241 crossConstraintMap = new HashMap<String,HashSet<HasCrossConstraints>>(); 242 crossConstraints.put(namespace, crossConstraintMap); 243 } 244 HashSet<HasCrossConstraints> fieldDescriptors = crossConstraintMap.get(path); 245 if(fieldDescriptors == null){ 246 fieldDescriptors = new HashSet<HasCrossConstraints>(); 247 crossConstraintMap.put(path, fieldDescriptors); 248 } 249 fieldDescriptors.add(fd); 250 } 251 252 253 254 public HashSet<HasCrossConstraints> getCrossConstraint(String namespace, String path){ 255 if(namespace==null){ 256 namespace="_default"; 257 } 258 HashMap<String,HashSet<HasCrossConstraints>> crossConstraintMap = crossConstraints.get(namespace); 259 if(crossConstraintMap!=null){ 260 return crossConstraintMap.get(path); 261 } 262 return null; 263 } 264 public void clearCrossConstraintMap(String namespace){ 265 if(namespace==null){ 266 namespace="_default"; 267 } 268 crossConstraints.remove(namespace); 269 } 270 public void putPathToFieldMapping(String namespace, String path, FieldDescriptor fd){ 271 if(namespace==null){ 272 namespace="_default"; 273 } 274 275 HashMap<String,FieldDescriptor> pathToField = pathToFieldMapping.get(namespace); 276 if(pathToField==null){ 277 pathToField = new HashMap<String,FieldDescriptor>(); 278 pathToFieldMapping.put(namespace, pathToField); 279 } 280 pathToField.put(path, fd); 281 } 282 283 public FieldDescriptor getPathToFieldMapping(String namespace, String path){ 284 if(namespace==null){ 285 namespace="_default"; 286 } 287 288 HashMap<String,FieldDescriptor> pathToField = pathToFieldMapping.get(namespace); 289 if(pathToField!=null){ 290 return pathToField.get(path); 291 } 292 return null; 293 } 294 public void clearPathToFieldMapping(String namespace){ 295 if(namespace==null){ 296 namespace="_default"; 297 } 298 pathToFieldMapping.remove(namespace); 299 } 300 301 /** 302 * Removes the bidirectional mapping for all paths that start with the path prefix 303 * This means if Field A had a dependency on Field B, and you cleared A, first all mappings with 304 * dependencies to A would be removed, then all mappings with dependencies to A would be removed. 305 * @param namespace 306 * @param pathPrefix 307 */ 308 public void clearCrossConstraintsWithStartingPath(String namespace, String pathPrefix){ 309 if(namespace==null){ 310 namespace="_default"; 311 } 312 //First delete any cross constraint mappings based on this field 313 HashMap<String,HashSet<HasCrossConstraints>> crossConstraintMap = crossConstraints.get(namespace); 314 if(crossConstraintMap!=null){ 315 Iterator<Map.Entry<String,HashSet<HasCrossConstraints>>> constraintMapIter = crossConstraintMap.entrySet().iterator(); 316 while(constraintMapIter.hasNext()){ 317 Map.Entry<String,HashSet<HasCrossConstraints>> entry = constraintMapIter.next(); 318 if(entry.getKey().startsWith(pathPrefix)){ 319 constraintMapIter.remove(); 320 } 321 } 322 323 //Find all the fieldDescriptors that start with the prefix and remove the cross constraint mapping to them 324 HashMap<String,FieldDescriptor> pathToField = pathToFieldMapping.get(namespace); 325 if(pathToField!=null){ 326 Iterator<Entry<String, FieldDescriptor>> pathMapIter = pathToField.entrySet().iterator(); 327 while(pathMapIter.hasNext()){ 328 Entry<String, FieldDescriptor> entry = pathMapIter.next(); 329 if(entry.getKey().startsWith(pathPrefix)){ 330 FieldDescriptor fd = entry.getValue(); 331 if(fd.getFieldWidget()!=null && fd.getFieldWidget() instanceof HasCrossConstraints && ((HasCrossConstraints)fd.getFieldWidget()).getCrossConstraints()!=null){ 332 //Loop through the constraint paths and remove any mapping to the existing field descriptor 333 for(String path:((HasCrossConstraints)fd.getFieldWidget()).getCrossConstraints()){ 334 HashSet<HasCrossConstraints> set = crossConstraintMap.get(path); 335 if(set!=null){ 336 set.remove(fd.getFieldWidget()); 337 } 338 } 339 } 340 } 341 } 342 } 343 } 344 } 345 346 347 public HashSet<HasCrossConstraints> getCrossConstraints(String namespace) { 348 if(namespace==null){ 349 namespace="_default"; 350 } 351 HashSet<HasCrossConstraints> results = new HashSet<HasCrossConstraints>(); 352 HashMap<String,HashSet<HasCrossConstraints>> crossConstraintMap = crossConstraints.get(namespace); 353 if(crossConstraintMap!=null){ 354 for(HashSet<HasCrossConstraints> fds: crossConstraintMap.values()){ 355 results.addAll(fds); 356 } 357 } 358 return results; 359 } 360 361 public String getParentPath() { 362 return parentPath; 363 } 364 365 public void setParentPath(String parentPath) { 366 this.parentPath = parentPath; 367 } 368 369 // public void putDefaultValueMapping(String namespace, 370 // FieldDescriptor fieldDescriptor, String defaultValuePath) { 371 // if(namespace==null){ 372 // namespace="_default"; 373 // } 374 // HashMap<FieldDescriptor, String> defaultValueMap = defaultValueMapping.get(namespace); 375 // if(defaultValueMap==null){ 376 // defaultValueMap = new HashMap<FieldDescriptor, String>(); 377 // defaultValueMapping.put(namespace, defaultValueMap); 378 // } 379 // defaultValueMap.put(fieldDescriptor, defaultValuePath); 380 // } 381 // 382 // public HashMap<FieldDescriptor, String> getDefaultValueMapping(String namespace) { 383 // if(namespace==null){ 384 // namespace="_default"; 385 // } 386 // HashMap<FieldDescriptor, String> result = defaultValueMapping.get(namespace); 387 // if(result==null){ 388 // result = new HashMap<FieldDescriptor, String>(); 389 // } 390 // return result; 391 // } 392 // public void clearDefaultValueMapping(String namespace){ 393 // if(namespace==null){ 394 // namespace="_default"; 395 // } 396 // defaultValueMapping.remove(namespace); 397 // } 398 399 }