From: Chad B. <cwb...@us...> - 2008-07-24 21:03:34
|
User: cwbrandon Date: 08/07/24 14:03:44 Modified: andromda-jsf2/src/main/resources/templates/jsf2/utils JsfUtils.java.vsl andromda-jsf2/src/main/resources/templates/jsf2/controllers Controller.java.vsl Log: Add ability to prevent more than one execution of an action upon either refreshs or multiple clicks (only enabled for portlets at this point). Revision Changes Path 1.8 +37 -0 cartridges/andromda-jsf2/src/main/resources/templates/jsf2/utils/JsfUtils.java.vsl Index: JsfUtils.java.vsl =================================================================== RCS file: /cvsroot/andromdaplugins/cartridges/andromda-jsf2/src/main/resources/templates/jsf2/utils/JsfUtils.java.vsl,v retrieving revision 1.7 retrieving revision 1.8 diff -u -w -r1.7 -r1.8 --- JsfUtils.java.vsl 1 Jul 2008 15:42:41 -0000 1.7 +++ JsfUtils.java.vsl 24 Jul 2008 21:03:44 -0000 1.8 @@ -342,6 +342,43 @@ } /** + * Finds the command that uses the action method on the given component. + * + * @param component the component from which to start the search. + * @param actionMethod the action method (i.e. controller.myMethod) + * @return the component or null of not found. + */ + public static javax.faces.component.UICommand findCommand(final javax.faces.component.UIComponent component, final String actionMethod) + { + javax.faces.component.UICommand found = null; + if (component instanceof javax.faces.component.UICommand) + { + final javax.faces.el.MethodBinding action = ((javax.faces.component.UICommand)component).getAction(); + if (action != null) + { + final String methodName = action.getExpressionString() != null ? action.getExpressionString().replaceAll(".\\{|\\}", "") : null; + if (actionMethod.equals(methodName)) + { + found = (javax.faces.component.UICommand)component; + } + } + } + if (found == null && component != null) + { + for (final java.util.Iterator iterator = component.getFacetsAndChildren(); iterator.hasNext();) + { + final javax.faces.component.UIComponent childComponent = (javax.faces.component.UIComponent)iterator.next(); + found = findCommand(childComponent, actionMethod); + if (found != null) + { + break; + } + } + } + return found; + } + + /** * Uses the converter identified by converterId to convert the value to a String. * @value the value to be converted * @converterId the id of the converter to be used 1.25 +136 -44 cartridges/andromda-jsf2/src/main/resources/templates/jsf2/controllers/Controller.java.vsl Index: Controller.java.vsl =================================================================== RCS file: /cvsroot/andromdaplugins/cartridges/andromda-jsf2/src/main/resources/templates/jsf2/controllers/Controller.java.vsl,v retrieving revision 1.24 retrieving revision 1.25 diff -u -w -r1.24 -r1.25 --- Controller.java.vsl 22 Jul 2008 16:08:17 -0000 1.24 +++ Controller.java.vsl 24 Jul 2008 21:03:44 -0000 1.25 @@ -53,37 +53,51 @@ #if ($formPopulationOperationRequired) final $action.fullyQualifiedFormImplementationName form = this.$action.formImplementationGetter; - - // - pass any properties from the previous form along - ${managedBeansPackage}.${formPopulatorName}.populateForm(currentForm, form); - // - populate the form with any event attributes that may match - // IMPORTANT: it isn't possible to automatically populate any property named "id" since that - // is a reserved name in JSF (the id of a component), therefore we have to unfortunately ignore any availble "id" attribute - ${managedBeansPackage}.${formPopulatorName}.populateFormFromPropertyMap( - form, form.getDateTimeFormatters(), (java.util.Map)this.getRequestAttribute(ACTION_EVENT_ATTRIBUTES), new String[] {"id"}); - // - populate the form with any request attributes that may match - ${managedBeansPackage}.${formPopulatorName}.populateFormFromRequestAttributes(form, form.getDateTimeFormatters(), false); - // - populate the form with any request parameters that may match - ${managedBeansPackage}.${formPopulatorName}.populateFormFromPropertyMap( - form, form.getDateTimeFormatters(), this.getContext().getExternalContext().getRequestParameterMap()); -#end - try - { -#if (!$action.formFields.empty) this.setForm("$action.formKey", form, true); #end - forward = #processTransition($action) - final javax.faces.application.FacesMessage.Severity messageSeverity = this.getMaximumMessageSeverity(); - if (messageSeverity != null && javax.faces.application.FacesMessage.SEVERITY_ERROR.getOrdinal() <= messageSeverity.getOrdinal()) +## - For now we'll just have the transaction checking in portlets (might be worth while to add to standalone at some point) +#set($indent = "") +#if ($portlet) +#set($indent = " ") + if (this.isTransactionValid("${controller.beanName}.${action.triggerName}")) { +#end +#if ($formPopulationOperationRequired) + ${indent}// - pass any properties from the previous form along + ${indent}${managedBeansPackage}.${formPopulatorName}.populateForm(currentForm, form); + ${indent}// - populate the form with any event attributes that may match + ${indent}// IMPORTANT: it isn't possible to automatically populate any property named "id" since that + ${indent}// is a reserved name in JSF (the id of a component), therefore we have to unfortunately ignore any availble "id" attribute + ${indent}${managedBeansPackage}.${formPopulatorName}.populateFormFromPropertyMap( + ${indent}form, form.getDateTimeFormatters(), (java.util.Map)this.getRequestAttribute(ACTION_EVENT_ATTRIBUTES), new String[] {"id"}); + ${indent}// - populate the form with any request attributes that may match + ${indent}${managedBeansPackage}.${formPopulatorName}.populateFormFromRequestAttributes(form, form.getDateTimeFormatters(), false); + ${indent}// - populate the form with any request parameters that may match + ${indent}${managedBeansPackage}.${formPopulatorName}.populateFormFromPropertyMap( + ${indent}form, form.getDateTimeFormatters(), this.getContext().getExternalContext().getRequestParameterMap()); +#end + ${indent}forward = #processTransition($action) +#if ($portlet) + ${indent}this.setLastForward(forward); +#end + ${indent}final javax.faces.application.FacesMessage.Severity messageSeverity = this.getMaximumMessageSeverity(); + ${indent}if (messageSeverity != null && javax.faces.application.FacesMessage.SEVERITY_ERROR.getOrdinal() <= messageSeverity.getOrdinal()) + ${indent}{ #if ($formPopulationOperationRequired) // - copy any messages to the 'currentForm' - org.apache.commons.beanutils.PropertyUtils.setProperty(currentForm, - "$formMessagesProperty", org.apache.commons.beanutils.PropertyUtils.getProperty(form, "$formMessagesProperty")); + ${indent}org.apache.commons.beanutils.PropertyUtils.setProperty(currentForm, + ${indent}"$formMessagesProperty", org.apache.commons.beanutils.PropertyUtils.getProperty(form, "$formMessagesProperty")); #end - this.setForm("$action.formKey", currentForm, $portlet); - } + ${indent}this.setForm("$action.formKey", currentForm, $portlet); + ${indent}} #saveMessages($action " ") +#if ($portlet) + } + else + { + forward = this.getLastForward(); + } +#end #if (!$action.formFields.empty && $action.formResetRequired) form.reset(); #end @@ -92,24 +106,19 @@ { logger.error(throwable); this.setForm("$action.formKey", currentForm, $portlet); - final String messageKey = ${managedBeansPackage}.${patternMatchingExceptionHandler}.instance().handleException(throwable); - if(org.apache.commons.lang.StringUtils.isEmpty(messageKey)) - { - throw throwable; - } - else + try { + final String messageKey = ${managedBeansPackage}.${patternMatchingExceptionHandler}.instance().handleException(throwable); + // - the exception is re-thrown by the exception handler and handled by the catch below if it can't get a messageKey + // (no reason to check for presence of messageKey) this.addErrorMessage(${managedBeansPackage}.Messages.get(messageKey, null)); } - } - } - catch (final Throwable throwable) + catch (Throwable exception) { - this.setForm("$action.formKey", currentForm, $portlet); - this.addExceptionMessage(throwable); // - set the forward to null so that we stay on the current view forward = null; - logger.error(throwable); + this.addExceptionMessage(exception); + } } return forward; #end @@ -734,5 +743,88 @@ this.setPortletMode(javax.portlet.PortletMode.HELP); return "${controller.useCase.portletHelpForwardName}"; } + + /** + * Indicates whether or not the current transaction is valid (i.e. checks + * that the transaction token - if available - is different than what is stored + * for the last transaction token). + * @param actionName the action name. + * @return whether or not transaction is valid + */ + protected boolean isTransactionValid(final String actionName) + { + boolean valid = true; + final String transactionTokeName = this.getTransactionTokenName(); + if (transactionTokeName != null) + { + final javax.faces.component.UIComponent command = ${managedBeansPackage}.JsfUtils.findCommand( + javax.faces.context.FacesContext.getCurrentInstance().getViewRoot(), actionName); + final String currentToken = command != null ? (String)command.getAttributes().get(transactionTokeName) : null; + if (currentToken != null) + { + final String lastToken = (String)this.getSessionAttribute( + transactionTokeName); + valid = !currentToken.equals(lastToken); + if (valid) + { + this.setSessionAttribute( + transactionTokeName, currentToken); + } + } + } + return valid; + } + + /** + * Gets the name of the attribute that stores the transaction token. + * + * @return the name of the transaction token or null if not available. + */ + protected String getTransactionTokenName() + { + String transactionTokenName = null; + try + { + final Class transactionTokenClass = Thread.currentThread().getContextClassLoader().loadClass( + "org.andromda.cartridges.jsf2.component.TransactionToken"); + transactionTokenName = (String)transactionTokenClass.getField("TRANSACTION_TOKEN").get(null); + } + catch (Exception exception) + { + if (logger.isDebugEnabled()) + { + logger.debug(exception); + } + } + return transactionTokenName; + } + + /** + * The variable that stores the last forward. + */ + private static final String LAST_FORWARD = "AndroMDA_LastForward"; + + /** + * Gets the current value of the last forward. + * + * @return the last forward. + */ + private String getLastForward() + { + return (String)this.getSessionAttribute(LAST_FORWARD); + } + + /** + * Sets the current value of the last forward. + * + * @param forward the last forward + */ + private void setLastForward(String forward) + { + if (forward != null) + { + this.setSessionAttribute(LAST_FORWARD, forward); + } + } #end } \ No newline at end of file |