| 1 64 65 package com.jcorporate.expresso.core.controller; 66 67 68 import com.jcorporate.expresso.core.ExpressoConstants; 69 import com.jcorporate.expresso.core.ExpressoSchema; 70 import com.jcorporate.expresso.core.controller.session.PersistentSession; 71 import com.jcorporate.expresso.core.db.DBException; 72 import com.jcorporate.expresso.core.dbobj.Schema; 73 import com.jcorporate.expresso.core.dbobj.SchemaFactory; 74 import com.jcorporate.expresso.core.i18n.Messages; 75 import com.jcorporate.expresso.core.jsdkapi.GenericDispatcher; 76 import com.jcorporate.expresso.core.misc.ConfigManager; 77 import com.jcorporate.expresso.core.misc.ConfigurationException; 78 import com.jcorporate.expresso.core.misc.DateTime; 79 import com.jcorporate.expresso.core.misc.EventHandler; 80 import com.jcorporate.expresso.core.misc.SerializableString; 81 import com.jcorporate.expresso.core.misc.StringUtil; 82 import com.jcorporate.expresso.core.security.DelayThread; 83 import com.jcorporate.expresso.core.security.User; 84 import com.jcorporate.expresso.core.servlet.CheckLogin; 85 import com.jcorporate.expresso.kernel.util.ClassLocator; 86 import com.jcorporate.expresso.kernel.util.FastStringBuffer; 87 import com.jcorporate.expresso.services.dbobj.ControllerSecurity; 88 import com.jcorporate.expresso.services.dbobj.RegistrationDomain; 89 import com.jcorporate.expresso.services.dbobj.Setup; 90 import org.apache.commons.beanutils.BeanUtils; 91 import org.apache.log4j.Logger; 92 import org.apache.struts.Globals; 93 import org.apache.struts.action.Action; 94 import org.apache.struts.action.ActionForm; 95 import org.apache.struts.action.ActionForward; 96 import org.apache.struts.action.ActionMapping; 97 import org.apache.struts.config.ActionConfig; 98 import org.apache.struts.config.ForwardConfig; 99 import org.apache.struts.upload.MultipartRequestHandler; 100 101 import javax.servlet.ServletException ; 102 import javax.servlet.http.HttpServletRequest ; 103 import javax.servlet.http.HttpServletResponse ; 104 import java.io.ByteArrayOutputStream ; 105 import java.io.IOException ; 106 import java.io.PrintStream ; 107 import java.io.Serializable ; 108 import java.lang.reflect.InvocationTargetException ; 109 import java.lang.reflect.Method ; 110 import java.util.ArrayList ; 111 import java.util.Enumeration ; 112 import java.util.Hashtable ; 113 import java.util.Iterator ; 114 import java.util.Locale ; 115 import java.util.Stack ; 116 import java.util.Vector ; 117 118 119 150 public abstract class Controller 151 extends Action 152 implements Serializable { 153 156 private static Logger log = Logger.getLogger(Controller.class); 157 158 162 protected Logger mLog = null; 163 164 167 public final static String RESPONSE_KEY = ExpressoConstants.CONTROLLER_RESPONSE_KEY; 168 171 public final static String ORIGINAL_URL_KEY = ExpressoConstants.CONTROLLER_ORIGINAL_URL_KEY; 172 175 public final static String REQUEST_KEY = ExpressoConstants.CONTROLLER_REQUEST_KEY; 176 177 180 public final static String NEWSTATE_EXCEPTION_KEY = ExpressoConstants.NEWSTATE_EXCEPTION_KEY; 181 182 183 public final static String CTL_SUCC_TRAN = "controllerSuccessReturn"; 185 public final static String CTL_SUCC_CTL = "controllerSuccessReturnController"; 186 public final static String CTL_SUCC_STATE = "controllerSuccessReturnState"; 187 public final static String STATE_SUCC_TRAN = "stateSuccessReturn"; 188 public final static String STATE_SUCC_CTL = "stateSuccessReturnController"; 189 public final static String STATE_SUCC_STATE = "stateSuccessReturnState"; 190 public final static String STATE_ERR_TRAN = "stateErrorReturn"; 191 public final static String STATE_ERR_CTL = "stateErrorReturnController"; 192 public final static String STATE_ERR_STATE = "stateErrorReturnState"; 193 public final static String RETURN_TO_SENDER_TRAN = "returnToSender"; 194 195 196 199 public static final String STATE_PARAM_KEY = "state"; 200 201 204 public static final String CONTROLLER_PARAM_KEY = "controller"; 205 206 207 208 private static Hashtable initialStates = new Hashtable (); 209 210 213 private static Hashtable schemas = new Hashtable (); 214 215 216 221 private static Hashtable states = new Hashtable (); 222 223 224 228 private static final Class [] newStateParams = { 229 java.lang.String .class, 230 com.jcorporate.expresso.core.controller.ControllerRequest.class 231 }; 232 233 234 237 private static final Class [] stateHandlerParams = { 238 com.jcorporate.expresso.core.controller.ControllerRequest.class, 239 com.jcorporate.expresso.core.controller.ControllerResponse.class 240 }; 241 242 245 private static final Class [] servletStateHandlerParams = { 246 com.jcorporate.expresso.core.controller.ServletControllerRequest.class, 247 com.jcorporate.expresso.core.controller.ControllerResponse.class 248 }; 249 250 251 264 private ArrayList promptStates = new ArrayList (3); 265 266 267 280 private ArrayList handleStates = new ArrayList (3); 281 282 private State finalState; 283 284 private Transition controllerChainingTransition = null; 285 286 private Transition controllerSecurityTransition = null; 287 288 289 292 public Controller() { 293 294 } 295 296 297 306 protected void addFinalState(State newFinalState) 307 throws NonHandleableException { 308 if (promptStates.contains(newFinalState) || 309 handleStates.contains(newFinalState)) { 310 throw new NonHandleableException("Final state must not be the same as any of the paired states."); 311 } 312 313 314 finalState = newFinalState; 315 addState(newFinalState); 316 317 318 if (StringUtil.notNull(getInitialState()).equals("")) { 320 setInitialState(newFinalState.getName()); 321 } 322 } 323 324 337 protected void addPromptTransitions(State nextState, 338 ControllerResponse response) 339 throws ControllerException { 340 341 342 if (isPromptState(nextState)) { 344 String previousPromptState = previousPromptState(nextState); 345 346 347 if (previousPromptState != null) { 348 Transition previousTransition = new Transition(); 349 previousTransition.setControllerObject(getClass().getName()); 350 previousTransition.setState(previousPromptState); 351 previousTransition.setName("previous"); 352 previousTransition.setLabel("Previous"); 353 response.addTransition(previousTransition); 354 } 355 356 357 Transition nextTransition = null; 359 String nextPromptState = nextPromptState(nextState); 360 361 362 if (nextPromptState != null) { String nextHandleState = nextHandleState(nextState); 364 365 366 nextTransition = new Transition(); 372 nextTransition.setControllerObject(getClass().getName()); 373 nextTransition.setState(nextHandleState); 374 nextTransition.setName("next"); 375 nextTransition.setLabel("Next"); 376 nextTransition.addParam(STATE_SUCC_STATE, nextPromptState); nextTransition.addParam(STATE_SUCC_CTL, 378 response.getControllerClass()); 379 } else { State finalState = getFinalState(); 381 382 383 if (finalState == null) { 384 throw new ControllerException("Final state must exist."); 385 } 386 387 388 nextTransition = new Transition(); 389 nextTransition.setControllerObject(getClass().getName()); 390 nextTransition.setState(finalState.getName()); 391 nextTransition.setName("next"); 392 nextTransition.setLabel(finalState.getDescription()); 393 } 394 395 396 response.addTransition(nextTransition); 397 } 398 } 399 400 407 protected void addState(State newState) { 408 try { 409 newState.setController(this); 410 } catch (ControllerException ce) { 411 log.error("Unable to set controller", ce); 412 } 413 414 415 Hashtable myStateList = (Hashtable ) states.get(getClass().getName()); 416 417 418 if (myStateList == null) { 419 myStateList = new Hashtable (); 420 states.put(getClass().getName(), myStateList); 421 } 422 423 424 myStateList.put(newState.getName(), newState); 425 } 426 427 428 438 protected void addStatePairing(State promptState, State handleState, 439 String stateFormClass) 440 throws NonHandleableException { 441 if (promptState == null || handleState == null) { 442 throw new NonHandleableException("Can't add null state in pairing."); 443 } 444 if (finalState != null) { 447 throw new NonHandleableException("Can't add states once final state has been added."); 448 } 449 if (promptStates.contains(promptState) || 450 promptStates.contains(handleState) || 451 handleStates.contains(promptState) || 452 handleStates.contains(handleState)) { 453 throw new NonHandleableException("Paired states must be unique."); 454 } 455 456 457 promptState.setStateFormClass(stateFormClass); 458 handleState.setStateFormClass(stateFormClass); 459 promptStates.add(promptState); 460 handleStates.add(handleState); 461 addState(promptState); 462 addState(handleState); 463 464 465 if (StringUtil.notNull(getInitialState()).equals("")) { 467 setInitialState(promptState.getName()); 468 } 469 470 471 Transition errorTransition = new Transition(); 474 errorTransition.setState(promptState.getName()); 475 errorTransition.setControllerObject(getClass().getName()); 476 handleState.setErrorTransition(errorTransition); 477 } 478 479 488 protected ActionForm findControllerForm(ControllerRequest request) 489 throws ControllerException { 490 ActionConfig config = ConfigManager.getActionConfig("", getClass().getName(), null); 491 if (config == null) { 494 return null; 495 } 496 497 String controllerFormAttribute = config.getAttribute(); 498 499 500 if (controllerFormAttribute == null) { return null; 502 } 503 504 505 PersistentSession session = request.getSession(); 507 508 509 if ("request".equals(config.getScope())) { 510 511 512 return (ActionForm) session.getAttribute(controllerFormAttribute); 514 } else { 515 return (ActionForm) session.getPersistentAttribute(controllerFormAttribute); 516 } 517 } 518 519 527 protected Transition getControllerChainingTransition() { 528 return controllerChainingTransition; 529 } 530 531 537 protected Transition getControllerSecurityTransition() { 538 return controllerSecurityTransition; 539 } 540 541 546 public State getFinalState() { 547 return finalState; 548 } 549 550 557 public String getInitialState() { 558 return (String ) initialStates.get(getClass().getName()); 559 } 560 561 562 567 protected final String getSchema() { 568 Stack mySchemaStack = (Stack ) schemas.get(getClass().getName()); 569 570 571 if (mySchemaStack == null) { 572 setSchema(ExpressoSchema.class.getName()); 573 mySchemaStack = (Stack ) schemas.get(getClass().getName()); 574 } 575 576 String returnValue = (String ) mySchemaStack.peek(); 577 return returnValue; 578 } 579 580 581 587 protected Schema getSchemaInstance() { 588 return SchemaFactory.getInstance().getSchema(this.getSchema()); 589 } 590 591 592 599 public synchronized Stack getSchemaHierarchy() { 600 return getSchemaStack(); 601 } 602 603 608 public synchronized Stack getSchemaStack() { 609 Stack s = (Stack ) schemas.get(getClass().getName()); 610 if (s == null) { 611 s = new Stack (); 612 schemas.put(this.getClass().getName(), s); 613 } 614 615 if (s.isEmpty()) { 616 s.push(com.jcorporate.expresso.core.ExpressoSchema.class.getName()); 617 } 618 619 return s; 620 } 621 622 628 public final State getState(String stateName) { 629 Hashtable myStateList = (Hashtable ) states.get(getClass().getName()); 630 631 632 if (myStateList == null) { 633 return null; 634 } 635 636 637 State stateClass = (State) myStateList.get(stateName); 638 639 640 if (stateClass == null) { 641 return null; 642 } 643 try { 644 State newStateClass = (State) stateClass.clone(); 645 newStateClass.setController(this); 646 647 648 return newStateClass; 649 } catch (CloneNotSupportedException cne) { 650 log.error("Unable to clone " + "State object '" + stateClass + 651 "'", cne); 652 } catch (ControllerException ce) { 653 log.error("Unable to clone " + "State object '" + stateClass + 654 "'", ce); 655 } 656 657 658 return null; 659 } 660 661 662 667 public final Hashtable getStates() { 668 Hashtable myStateList = (Hashtable ) states.get(getClass().getName()); 669 670 if (myStateList == null) { 671 return null; 672 } 673 674 return myStateList; 675 } 676 677 678 688 protected String getString(String stringCode) { 689 return this.getString(stringCode, new Object [0]); 690 } 691 692 693 704 protected String getString(String stringCode, Object [] args) { 705 String result = stringCode; 706 Stack s = (Stack ) schemas.get(this.getClass().getName()); 707 708 if (s == null || s.isEmpty()) { 709 result = Messages.getString(getSchema(), stringCode, args); 710 } else { 711 Locale theLocale = Messages.getDefaultLocale(); 712 result = Messages.getString(s, theLocale, stringCode, args); 713 } 714 715 return result; 716 } 717 718 719 724 public String getTitle() { 725 return ("No Title"); 726 } 727 728 729 744 protected void handleException(HttpServletRequest req, 745 ControllerRequest creq, String dbName, 746 String userName, Throwable theException) 747 throws ServletException { 748 if (StringUtil.notNull(dbName).equals("")) { 749 dbName = "default"; 750 } 751 752 if (creq == null || dbName == null || req == null || userName == null) { 753 log.error("Error handling exception", theException); 754 throw new ServletException ("ControllerRequest Error", theException); 755 } 756 757 try { 758 ControllerResponse errorResponse = new ControllerResponse(); 759 errorResponse.setRequest(creq); 760 errorResponse.setTitle(getTitle()); 761 errorResponse.setSchemaStack((java.util.Stack ) this.getSchemaStack().clone()); 762 errorResponse.setControllerClass(getClass().getName()); 763 764 765 766 boolean showStack = true; 767 768 769 try { 770 if (ConfigManager.getContext(dbName) != null) { 771 showStack = ConfigManager.getContext(dbName).showStackTrace(); 772 } 773 } catch (ConfigurationException ce) { 774 throw new ServletException (ce); 775 } 776 if (showStack) { 777 if (theException != null) { 778 ByteArrayOutputStream bos = new ByteArrayOutputStream (); 779 theException.printStackTrace(new PrintStream (bos)); 780 errorResponse.addOutput(new Output("stackTrace", 781 bos.toString())); 782 } else { 783 errorResponse.addOutput(new Output("stackTrace", 784 "No stack trace was available")); 785 } 786 } else { 787 errorResponse.addOutput(new Output("stackTrace", 788 "Stack trace display is not " + "enabled.")); 789 } 790 791 792 errorResponse.addOutput(new Output("exceptionMessage", 793 theException.getMessage())); 794 795 796 if (theException instanceof com.jcorporate.expresso.kernel.exception.ChainedException) { 797 com.jcorporate.expresso.kernel.exception.ChainedException c = (com.jcorporate.expresso.kernel.exception.ChainedException) theException; 798 Throwable nestedException = c.getNested(); 799 800 801 if (nestedException != null) { 802 String nested = StringUtil.notNull(c.getNested().getMessage()); 803 804 805 if (theException.getMessage().indexOf(nested) == -1) { 806 errorResponse.addOutput(new Output("nestedMessage", 807 nested)); 808 } 809 } 810 if (c.getErrorNumber() != 0) { 811 errorResponse.addOutput(new Output("errorNumber", 812 &nb
|