1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.student.common.ui.client.mvc;
17
18 import java.util.HashMap;
19 import java.util.Iterator;
20 import java.util.Map;
21
22 import org.kuali.student.common.rice.authorization.PermissionType;
23 import org.kuali.student.common.ui.client.application.ViewContext;
24 import org.kuali.student.common.ui.client.configurable.mvc.LayoutController;
25 import org.kuali.student.common.ui.client.mvc.breadcrumb.BreadcrumbSupport;
26 import org.kuali.student.common.ui.client.mvc.history.HistoryManager;
27 import org.kuali.student.common.ui.client.mvc.history.HistorySupport;
28 import org.kuali.student.common.ui.client.mvc.history.NavigationEvent;
29 import org.kuali.student.common.ui.client.security.AuthorizationCallback;
30 import org.kuali.student.common.ui.client.security.RequiresAuthorization;
31
32 import com.google.gwt.core.client.GWT;
33 import com.google.gwt.event.shared.GwtEvent.Type;
34 import com.google.gwt.event.shared.HandlerManager;
35 import com.google.gwt.event.shared.HandlerRegistration;
36 import com.google.gwt.user.client.Window;
37 import com.google.gwt.user.client.ui.Composite;
38 import com.google.gwt.user.client.ui.Widget;
39
40
41
42
43
44
45
46 public abstract class Controller extends Composite implements HistorySupport, BreadcrumbSupport{
47 public static final Callback<Boolean> NO_OP_CALLBACK = new Callback<Boolean>() {
48 @Override
49 public void exec(Boolean result) {
50
51 }
52 };
53
54 protected Controller parentController = null;
55 private View currentView = null;
56 private Enum<?> currentViewEnum = null;
57 private String defaultModelId = null;
58 protected ViewContext context = new ViewContext();
59 private final Map<String, ModelProvider<? extends Model>> models = new HashMap<String, ModelProvider<? extends Model>>();
60 private boolean fireNavEvents = true;
61 private HandlerManager applicationEventHandlers = new HandlerManager(this);
62
63 protected Controller() {
64 }
65
66
67
68
69
70
71
72
73 public <V extends Enum<?>> void showView(final V viewType){
74 this.showView(viewType, NO_OP_CALLBACK);
75 }
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97 public <V extends Enum<?>> void showView(final V viewType, final Callback<Boolean> onReadyCallback) {
98 GWT.log("showView " + viewType.toString(), null);
99 getView(viewType, new Callback<View>(){
100
101 @Override
102 public void exec(View result) {
103 View view = result;
104 if (view == null) {
105 onReadyCallback.exec(false);
106
107 }
108 beginShowView(view, viewType, onReadyCallback);
109
110 }});
111 }
112
113 private <V extends Enum<?>> void beginShowView(final View view, final V viewType, final Callback<Boolean> onReadyCallback){
114 beforeViewChange(viewType, new Callback<Boolean>(){
115
116 @Override
117 public void exec(Boolean result) {
118 if(result){
119 boolean requiresAuthz = (view instanceof RequiresAuthorization) && ((RequiresAuthorization)view).isAuthorizationRequired();
120
121 if (requiresAuthz){
122 ViewContext tempContext = new ViewContext();
123 if(view instanceof LayoutController){
124 tempContext = ((LayoutController) view).getViewContext();
125 }
126 else{
127 tempContext = view.getController().getViewContext();
128 }
129
130 PermissionType permType = (tempContext != null) ? tempContext.getPermissionType() : null;
131 if (permType != null) {
132 GWT.log("Checking permission type '" + permType.getPermissionTemplateName() + "' for view '" + view.toString() + "'", null);
133
134 ((RequiresAuthorization)view).checkAuthorization(permType, new AuthorizationCallback(){
135 public void isAuthorized() {
136 finalizeShowView(view, viewType, onReadyCallback);
137 }
138
139 public void isNotAuthorized(String msg) {
140 Window.alert(msg);
141 onReadyCallback.exec(false);
142 }
143 });
144 }
145 else {
146 GWT.log("Cannot find PermissionType for view '" + view.toString() + "' which requires authorization", null);
147 finalizeShowView(view, viewType, onReadyCallback);
148 }
149 } else {
150 GWT.log("Not Requiring Auth.", null);
151 finalizeShowView(view, viewType, onReadyCallback);
152 }
153 }
154 else{
155 onReadyCallback.exec(false);
156 }
157
158 }
159 });
160 }
161
162 private <V extends Enum<?>> void finalizeShowView(final View view, final V viewType, final Callback<Boolean> onReadyCallback){
163 if ((currentView == null) || currentView.beforeHide()) {
164 view.beforeShow(new Callback<Boolean>() {
165 @Override
166 public void exec(Boolean result) {
167 if (!result) {
168 GWT.log("showView: beforeShow yielded false " + viewType, null);
169 onReadyCallback.exec(false);
170 } else {
171 if (currentView != null) {
172 hideView(currentView);
173 }
174
175 currentViewEnum = viewType;
176 currentView = view;
177 GWT.log("renderView " + viewType.toString(), null);
178 if(fireNavEvents){
179 fireNavigationEvent();
180 }
181 renderView(view);
182 onReadyCallback.exec(true);
183
184 }
185 }
186 });
187 } else {
188 onReadyCallback.exec(false);
189 GWT.log("Current view canceled hide action", null);
190 }
191 }
192
193 protected void fireNavigationEvent() {
194
195
196
197 fireApplicationEvent(new NavigationEvent(Controller.this));
198
199
200 }
201
202
203
204
205
206
207 public View getCurrentView() {
208 return currentView;
209 }
210
211 public Enum<?> getCurrentViewEnum() {
212 return currentViewEnum;
213 }
214
215 public void setCurrentViewEnum(Enum<?> currentViewEnum) {
216 this.currentViewEnum = currentViewEnum;
217 }
218
219
220
221
222
223
224
225
226
227
228 public void setParentController(Controller controller) {
229 parentController = controller;
230 }
231
232
233
234
235
236
237
238 public Controller getParentController() {
239 if (parentController == null) {
240 parentController = Controller.findController(this);
241 }
242 return parentController;
243 }
244
245
246
247
248
249
250
251
252 public static Controller findController(Widget w) {
253 Controller result = null;
254 while (true) {
255 w = w.getParent();
256 if (w == null) {
257 break;
258 } else if (w instanceof Controller) {
259 result = (Controller) w;
260 break;
261 } else if (w instanceof View) {
262
263
264 result = ((View) w).getController();
265 break;
266 }
267 }
268 return result;
269 }
270
271
272
273
274
275
276
277
278
279
280
281
282
283 @SuppressWarnings("unchecked")
284 public void requestModel(final Class modelType, final ModelRequestCallback callback) {
285 requestModel((modelType == null) ? null : modelType.getName(), callback);
286 }
287
288 @SuppressWarnings("unchecked")
289 public void requestModel(final String modelId, final ModelRequestCallback callback) {
290 String id = (modelId == null) ? defaultModelId : modelId;
291
292 ModelProvider<? extends Model> p = models.get(id);
293 if (p != null) {
294 p.requestModel(callback);
295 } else if (getParentController() != null) {
296 parentController.requestModel(modelId, callback);
297 } else {
298 if (callback != null) {
299 callback.onRequestFail(new RuntimeException("The requested model was not found: " + modelId));
300 }
301 }
302 }
303
304 @SuppressWarnings("unchecked")
305 public void requestModel(final ModelRequestCallback callback) {
306 requestModel((String)null, callback);
307 }
308
309 public <T extends Model> void registerModel(String modelId, ModelProvider<T> provider) {
310 models.put(modelId, provider);
311 }
312
313 public String getDefaultModelId() {
314 return defaultModelId;
315 }
316 public void setDefaultModelId(String defaultModelId) {
317 this.defaultModelId = defaultModelId;
318 }
319
320
321
322
323
324
325
326
327
328
329 @SuppressWarnings("unchecked")
330 public HandlerRegistration addApplicationEventHandler(Type type, ApplicationEventHandler handler) {
331 if ((handler instanceof UncheckedApplicationEventHandler) && (getParentController() != null)) {
332 return parentController.addApplicationEventHandler(type, handler);
333 }
334 return applicationEventHandlers.addHandler(type, handler);
335 }
336
337
338
339
340
341
342 @SuppressWarnings("unchecked")
343 public void fireApplicationEvent(ApplicationEvent event) {
344
345
346 if ((event instanceof UncheckedApplicationEvent) && (getParentController() != null)) {
347 parentController.fireApplicationEvent(event);
348 }
349
350 applicationEventHandlers.fireEvent(event);
351
352 }
353
354
355
356
357
358
359 protected abstract void renderView(View view);
360
361
362
363
364
365
366 protected abstract void hideView(View view);
367
368
369
370
371
372
373
374
375 protected abstract <V extends Enum<?>> void getView(V viewType, Callback<View> callback);
376
377
378
379
380
381
382
383 public void beforeViewChange(Enum<?> viewChangingTo, Callback<Boolean> okToChangeCallback) {
384 okToChangeCallback.exec(true);
385 }
386
387
388
389
390 public abstract void showDefaultView(Callback<Boolean> onReadyCallback);
391
392 public abstract Enum<?> getViewEnumValue(String enumValue);
393
394
395
396
397
398
399
400 @Override
401 public String collectHistory(String historyStack) {
402 String token = getHistoryToken();
403 historyStack = historyStack + "/" + token;
404
405 if(currentView != null){
406 String tempHistoryStack = historyStack;
407 historyStack = currentView.collectHistory(historyStack);
408
409
410 if(historyStack == null){
411 historyStack = tempHistoryStack;
412 }
413 else if(historyStack != null && historyStack.isEmpty()){
414 historyStack = tempHistoryStack;
415 }
416 }
417 return historyStack;
418 }
419
420 protected String getHistoryToken() {
421 String historyToken = "";
422 if (currentViewEnum != null) {
423 historyToken = currentViewEnum.toString();
424 if(currentView != null && currentView instanceof Controller
425 && ((Controller)currentView).getViewContext() != null){
426 ViewContext context = ((Controller) currentView).getViewContext();
427 historyToken = HistoryManager.appendContext(historyToken, context);
428 }
429
430 }
431 return historyToken;
432 }
433
434
435
436
437
438
439
440
441
442
443
444
445
446 @Override
447 public void onHistoryEvent(String historyStack) {
448 final String nextHistoryStack = HistoryManager.nextHistoryStack(historyStack);
449 String[] tokens = HistoryManager.splitHistoryStack(nextHistoryStack);
450 if (tokens.length >= 1 && tokens[0] != null && !tokens[0].isEmpty()) {
451 final Map<String, String> tokenMap = HistoryManager.getTokenMap(tokens[0]);
452
453 String viewEnumString = tokenMap.get("view");
454 if (viewEnumString != null) {
455 final Enum<?> viewEnum = getViewEnumValue(viewEnumString);
456
457 if (viewEnum != null) {
458 getView(viewEnum, new Callback<View>(){
459
460 @Override
461 public void exec(View result) {
462 View theView = result;
463 boolean sameContext = true;
464 if(theView instanceof Controller){
465
466 ViewContext newContext = new ViewContext();
467 Iterator<String> tokenIt = tokenMap.keySet().iterator();
468 while(tokenIt.hasNext()){
469 String key = tokenIt.next();
470 if(key.equals(ViewContext.ID_ATR)){
471 newContext.setId(tokenMap.get(ViewContext.ID_ATR));
472 }
473 else if(key.equals(ViewContext.ID_TYPE_ATR)){
474 newContext.setIdType(tokenMap.get(ViewContext.ID_TYPE_ATR));
475 }
476
477 else if(!key.equals("view")){
478 newContext.setAttribute(key, tokenMap.get(key));
479 }
480 }
481
482 ViewContext viewContext = ((Controller) theView).getViewContext();
483 if(viewContext.compareTo(newContext) != 0){
484 ((Controller) theView).setViewContext(newContext);
485 sameContext = false;
486 }
487 }
488 if (currentViewEnum == null || !viewEnum.equals(currentViewEnum)
489 || !sameContext) {
490 beginShowView(theView, viewEnum, new Callback<Boolean>() {
491 @Override
492 public void exec(Boolean result) {
493 if (result) {
494 currentView.onHistoryEvent(nextHistoryStack);
495 }
496 }
497 });
498 } else if (currentView != null) {
499 currentView.onHistoryEvent(nextHistoryStack);
500 }
501 }
502 });
503
504 }
505 }
506 }
507 else{
508 this.showDefaultView(new Callback<Boolean>(){
509
510 @Override
511 public void exec(Boolean result) {
512 if(result){
513 currentView.onHistoryEvent(nextHistoryStack);
514 }
515
516 }
517 });
518 }
519
520 }
521
522
523
524
525
526
527
528
529 public void setViewContext(ViewContext viewContext){
530 this.context = viewContext;
531 }
532
533 public ViewContext getViewContext() {
534 return this.context;
535 }
536
537 public void resetCurrentView(){
538 currentView = null;
539 }
540
541 }