in ti/phase2/jars/core/src/java/org/apache/ti/pageflow/FlowControllerFactory.java [155:309]
public PageFlowController createPageFlow(Class pageFlowClass)
throws InstantiationException, IllegalAccessException {
if (!PageFlowController.class.isAssignableFrom(pageFlowClass)) {
return null;
}
//
// First check if this is a request for a "long lived" page flow. If so, try
// PageFlowUtils.getCurrentPageFlow again, with the longLived flag.
//
PageFlowController retVal = null;
String namespace = InternalUtils.inferNamespaceFromClassName(pageFlowClass.getName());
ModuleRegistrationHandler mrh = Handlers.get().getModuleRegistrationHandler();
ModuleConfig mc = mrh.getModuleConfig(namespace);
if (mc == null) {
_log.error("Struts module " + namespace + " not found for " + pageFlowClass.getName() + "; cannot create page flow.");
return null;
}
if (mc.isLongLivedFlow()) {
retVal = PageFlowUtils.getLongLivedPageFlow(namespace);
if (_log.isDebugEnabled()) {
if (retVal != null) {
_log.debug("Using long lived PageFlowController of type " + pageFlowClass.getName());
}
}
}
//
// First, see if this is a nested page flow that's already on the stack. Unless "renesting" is explicitly
// enabled, we don't want to allow another instance of this page flow to be nested. This is a common
// browser back-button problem:
// 1) request nested page flow A
// 2) request nested page flow B
// 3) press back button, and execute an action on A.
//
// This logic does not deal with immediate self-nesting (A->A), which is taken care of in
// PageFlowController.forwardTo(). Nested page flows can only self-nest by forwarding to the .jpf URI, not
// indirectly by executing actions on themselves (think about it -- that would be a disaster).
//
boolean createdNew = false;
boolean isNestable = mc.isNestedFlow();
PageFlowStack pfStack = PageFlowStack.get(false);
if (isNestable && (pfStack != null)) {
PageFlowConfig options = ConfigUtil.getConfig().getPageFlowConfig();
if ((options == null) || !options.isEnableSelfNesting()) {
int lastIndexOfJpfClass = pfStack.lastIndexOf(pageFlowClass);
if (lastIndexOfJpfClass != -1) {
retVal = pfStack.popUntil(lastIndexOfJpfClass);
retVal.persistInSession();
return retVal;
}
}
}
//
// OK, if it's not an existing long lived page flow, and if this wasn't a nested page flow already on the
// stack, then create a new instance.
//
if (retVal == null) {
if (_log.isDebugEnabled()) {
_log.debug("Creating PageFlowController of type " + pageFlowClass.getName());
}
retVal = (PageFlowController) getFlowControllerInstance(pageFlowClass);
createdNew = true;
}
//
// Store the previous PageFlowController on the nesting stack (if this one is nestable),
// or destroy the nesting stack.
//
if (isNestable) {
//
// Call create() on the newly-created page flow.
//
if (createdNew) {
retVal.create();
}
PageFlowController current = PageFlowUtils.getCurrentPageFlow();
if (current != null) {
if (_log.isDebugEnabled()) {
_log.debug("Pushing PageFlowController " + current + " onto the nesting stack");
}
if (pfStack == null) {
pfStack = PageFlowStack.get(true);
}
pfStack.push(current);
}
retVal.reinitialize();
retVal.persistInSession();
} else {
//
// Going to a non-nested pageflow. Blow away the pageflow stack.
//
if (pfStack != null) {
if (_log.isDebugEnabled()) {
_log.debug("Destroying the PageFlowController stack.");
}
//
// Start popping page flows until 1) there are none left on the stack, or 2) we find
// one of the type we're returning. If (2), we'll use that one (this means that executing
// an action on a nesting page flow while in a nested one will not destroy the nesting
// page flow only to create a new instance of it).
//
PageFlowController onStackAlready = pfStack.popUntil(retVal.getClass());
if (onStackAlready != null) {
if (_log.isDebugEnabled()) {
_log.debug("Found a page flow of type " + retVal.getClass() + " in the stack; " +
"using that instance and stopping destruction of the nesting stack.");
}
retVal = onStackAlready;
retVal.persistInSession();
} else {
//
// We're actually using the newly-created page flow, so call create() on it.
// Note that we make the call to persistInSession *before* create, so the previous flow's
// onDestroy() gets called before the new one's onCreate().
//
retVal.reinitialize();
retVal.persistInSession();
retVal.create();
}
} else {
//
// We're actually using the newly-created page flow, so call create() on it (*after* persisting
// in the session so the previous page flow's onDestroy() gets called before the new one's
// onCreate()).
//
retVal.reinitialize();
retVal.persistInSession();
if (createdNew) {
retVal.create();
}
}
}
return retVal;
}