/* * Copyright (C) 2005-2012 BetaCONCEPT Limited * * This file is part of Astroboa. * * Astroboa is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Astroboa is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Astroboa. If not, see <http://www.gnu.org/licenses/>. */ package org.betaconceptframework.astroboa.console.jsf; import java.lang.reflect.Method; import javax.faces.application.FacesMessage; import org.apache.commons.lang.StringUtils; import org.betaconceptframework.ui.jsf.utility.JSFUtilities; import org.jboss.seam.ScopeType; import org.jboss.seam.annotations.Name; import org.jboss.seam.annotations.Scope; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * This bean is used along with WEB-INF/pageComponents/confirmationDialog.xhtml * * in order to successfully pop up a confirmation dialog box * and upon confirmation to execute proper action. * * There is also the possibility to execute a post action as well, regardless if user has clicked on OK * or Cancel button. That is you may choose to execute one action if user clicks OK and right after that to execute * another action. * * In order to activate this utility, one must take the following steps : * * 1. Include in your page, facelet WEB-INF/pageComponents/confirmationDialog.xhtml * * 2. On the component that will trigger the action (in this example an a4j:commandLink) * user must specify attribute action with this bean method initiateConfirmation with the following parameters * * a. The bean instance which contains the method that will be called upon confirmation * b. The name of the method to be executed * c. A customized label to be displayed in the confirmation dialog box * d. A comma delimited string containing one or more component ids to be re rendered once action is completed, or null value * e. The arguments needed by the method to be executed separated by comma, or null if none is required * f. A javascript function to run when the "ok" action and the page re-rendering have finished. If none is provided then by default * a function that hides the dialogue is run. If you provide a function you do not need to take care hiding the dialog. This will be taken care * automatically * * 2.5 If you need to execute a post action as well you need the above parameters plus the following parameters for the post action * * a. The bean instance which contains the method that will be called after confirmation action has been performed or after user has clicked Cancel * b. The name of the method to be executed * c. An array of the arguments needed by the method to be executed, or null if none is required * * 3. On the component that will trigger the action, user must specify attribute oncomplete in order for the panel to be displayed * * 4. On the component that will trigger the action, user must specify the reRender attribute with the value * "confirmationDialogPanel" in order for the panel to display the proper messages. * * For example a click to the following link will create an instance of this bean and store * all necessary objects needed to complete action if confirmation is granted. * When user confirms the action, method 'permanentlyRemoveSelectedContentObject_UIAction' * is executed with the proper arguments and upon successful execution components * 'ajaxDynamicAreaPanel, topicTree, cmsTree, clipboardTable' are reRendered. * <pre> * <a4j:commandLink action="#{confirmationBean.initiateConfirmation('dialog.confirmation.delete.question', contentObjectList, 'permanentlyRemoveSelectedContentObject_UIAction', 'My Custom Message', 'ajaxDynamicAreaPanel, topicTree, cmsTree, clipboardTable', contentObjectUIWrapper.contentObject.id,contentObjectUIWrapper.contentObject.contentObjectType,contentObjectUIWrapper.contentObjectProperty['profile.created'].simpleTypeValue)}" oncomplete="openConfirmationDialog();" reRender="confirmationDialogPanel"> Link label </a4j:commandLink> * </pre> * * @author Gregory Chomatas (gchomatas@betaconcept.com) * @author Savvas Triantafyllou (striantafyllou@betaconcept.com) * */ @Name("confirmationBean") @Scope(ScopeType.PAGE) public class ConfirmationBean { protected final Logger logger = LoggerFactory.getLogger(this.getClass()); private Object beanWhoseMethodWillBeCalledOnClickOKButton; private String methodNameToBeExecutedOnClickOKButton; private Object[] argumentsOfMethodToBeExecutedOnClickOKButton; private Object beanWhoseMethodWillBeCalledAfterMethodFromOKButtonOrActionFromCancelButton; private String methodNameToBeExecutedAfterMethodFromOKButtonOrActionFromCancelButton; private Object[] argumentsOfMethodToBeExecutedAfterMethodFromOKButtonOrActionFromCancelButton; private String customizedConfirmationMessage; private String commaDelimitedReRenderComponentIds; private String messageKey; private String oncompleteJsFunction = "closeConfirmationDialog();"; public void proceedWithAction_UIAction(){ if (beanWhoseMethodWillBeCalledOnClickOKButton != null){ if (StringUtils.isBlank(methodNameToBeExecutedOnClickOKButton)){ logger.warn("No method name is available for bean {}.Action cannot procceed", beanWhoseMethodWillBeCalledOnClickOKButton.getClass().getName()); actionFail(); return; } //Find bean method Method beanMethod = retrieveMethod(beanWhoseMethodWillBeCalledOnClickOKButton,methodNameToBeExecutedOnClickOKButton); if (beanMethod == null){ logger.warn("No method found for name {} in bean {}.Action cannot procceed", methodNameToBeExecutedOnClickOKButton, beanWhoseMethodWillBeCalledOnClickOKButton.getClass().getName()); actionFail(); return; } //Invoke method try{ beanMethod.invoke(beanWhoseMethodWillBeCalledOnClickOKButton, argumentsOfMethodToBeExecutedOnClickOKButton); //all went well //Do not clear component ids to be rendered //as they are used after this method is completed proceedWithLastAction(false); } catch(Exception e){ logger.error("Exception while invoking method "+methodNameToBeExecutedOnClickOKButton +" in bean "+beanWhoseMethodWillBeCalledOnClickOKButton.getClass().getName(), e); actionFail(); } } else{ logger.warn("No bean is available. Action cannot procceed"); actionFail(); } } private void proceedWithLastAction(boolean clearReRenderIds){ if (beanWhoseMethodWillBeCalledAfterMethodFromOKButtonOrActionFromCancelButton == null) { clear(clearReRenderIds); return; } if (StringUtils.isBlank(methodNameToBeExecutedAfterMethodFromOKButtonOrActionFromCancelButton)){ logger.warn("No method name is available for bean {}.Action cannot procceed", beanWhoseMethodWillBeCalledAfterMethodFromOKButtonOrActionFromCancelButton.getClass().getName()); actionFail(); return; } //Find bean method Method beanMethod = retrieveMethod(beanWhoseMethodWillBeCalledAfterMethodFromOKButtonOrActionFromCancelButton,methodNameToBeExecutedAfterMethodFromOKButtonOrActionFromCancelButton); if (beanMethod == null){ logger.warn("No method found for name {} in bean {}.Action cannot procceed", methodNameToBeExecutedAfterMethodFromOKButtonOrActionFromCancelButton, beanWhoseMethodWillBeCalledAfterMethodFromOKButtonOrActionFromCancelButton.getClass().getName()); actionFail(); return; } //Invoke method try{ beanMethod.invoke(beanWhoseMethodWillBeCalledAfterMethodFromOKButtonOrActionFromCancelButton, argumentsOfMethodToBeExecutedAfterMethodFromOKButtonOrActionFromCancelButton); clear(clearReRenderIds); } catch(Exception e){ logger.error("Exception while invoking method "+methodNameToBeExecutedAfterMethodFromOKButtonOrActionFromCancelButton +" in bean "+beanWhoseMethodWillBeCalledAfterMethodFromOKButtonOrActionFromCancelButton.getClass().getName(), e); actionFail(); } } private void actionFail() { JSFUtilities.addMessage(null, "application.unknown.error.message", null, FacesMessage.SEVERITY_WARN); clear(true); } public void clear_UIAction() { proceedWithLastAction(true); } private void clear(boolean clearComponentIdsToBeRendered) { beanWhoseMethodWillBeCalledOnClickOKButton=null; beanWhoseMethodWillBeCalledAfterMethodFromOKButtonOrActionFromCancelButton=null; methodNameToBeExecutedOnClickOKButton=null; methodNameToBeExecutedAfterMethodFromOKButtonOrActionFromCancelButton=null; argumentsOfMethodToBeExecutedOnClickOKButton = null; argumentsOfMethodToBeExecutedAfterMethodFromOKButtonOrActionFromCancelButton = null; customizedConfirmationMessage = null; messageKey=null; if (clearComponentIdsToBeRendered){ commaDelimitedReRenderComponentIds = null; } } public void initiateConfirmation( String messageKey, Object beanWhoseMethodWillBeCalledOnClickOKButton, String methodNameToBeExceutedOnClickOKButton, String customizedConfirmationMessage, String reRenderComponentIds, String oncompleteJsFunction, Object... argumentsOfMethodToBeExecutedOnClickOKButton){ initiateConfirmationWithActionOnOKAndFinalAction(messageKey, beanWhoseMethodWillBeCalledOnClickOKButton, methodNameToBeExceutedOnClickOKButton, argumentsOfMethodToBeExecutedOnClickOKButton, null, null, null, customizedConfirmationMessage, reRenderComponentIds, oncompleteJsFunction); } public void initiateConfirmationWithActionOnOKAndFinalAction( String messageKey, Object beanWhoseMethodWillBeCalledOnClickOKButton, String methodNameToBeExceutedOnClickOKButton, Object[] argumentsOfMethodToBeExecutedOnClickOKButton, Object beanWhoseMethodWillBeCalledOnClickCancelButton, String methodNameToBeExceutedOnClickCancelButton, Object[] argumentsOfMethodToBeExecutedOnClickCancelButton, String customizedConfirmationMessage, String reRenderComponentIds, String oncompleteJsFunction){ this.messageKey = messageKey; this.beanWhoseMethodWillBeCalledOnClickOKButton = beanWhoseMethodWillBeCalledOnClickOKButton; this.methodNameToBeExecutedOnClickOKButton = methodNameToBeExceutedOnClickOKButton; this.argumentsOfMethodToBeExecutedOnClickOKButton =argumentsOfMethodToBeExecutedOnClickOKButton; this.beanWhoseMethodWillBeCalledAfterMethodFromOKButtonOrActionFromCancelButton = beanWhoseMethodWillBeCalledOnClickCancelButton; this.methodNameToBeExecutedAfterMethodFromOKButtonOrActionFromCancelButton = methodNameToBeExceutedOnClickCancelButton; this.argumentsOfMethodToBeExecutedAfterMethodFromOKButtonOrActionFromCancelButton =argumentsOfMethodToBeExecutedOnClickCancelButton; this.customizedConfirmationMessage = customizedConfirmationMessage; if (StringUtils.isNotBlank(oncompleteJsFunction)) { this.oncompleteJsFunction = oncompleteJsFunction + "; " + this.oncompleteJsFunction; } if (StringUtils.isNotBlank(reRenderComponentIds)) { this.commaDelimitedReRenderComponentIds = reRenderComponentIds; } else { this.commaDelimitedReRenderComponentIds = null; } } /** * @return the customizedConfirmationMessage */ public String getCustomizedConfirmationMessage() { return customizedConfirmationMessage; } /** * @return the commaDelimitedReRenderComponentIds */ public String getCommaDelimitedReRenderComponentIds() { return commaDelimitedReRenderComponentIds; } /** * @return the messageKey */ public String getMessageKey() { return messageKey; } public Object[] getEmptyArgumentArray() { return new Object[0]; } public Object[] getArrayForCommaDelimitedObjects(Object... objects ) { if (objects == null || objects.length == 0) { return getEmptyArgumentArray(); } return objects; } private Method retrieveMethod(Object bean, String methodName) { Method[] beanMethods = bean.getClass().getMethods(); for (Method beanMethod: beanMethods){ if (methodName.equals(beanMethod.getName())){ return beanMethod; } } return null; } public String getMethodNameToBeExecutedAfterMethodFromOKButtonOrActionFromCancelButton() { return methodNameToBeExecutedAfterMethodFromOKButtonOrActionFromCancelButton; } public String getOncompleteJsFunction() { return oncompleteJsFunction; } }