/** * Copyright 2010 the original author or authors. * * This file is part of openTruuls™. http://www.opentruuls.org/ * * openTruuls™ community edition is free software: you can * redistribute it and/or modify it under the terms of the * openTruuls™ public License which is based on the Apache * License 2.0 from the Apache Foundation. The only permission * for using openTruuls™ is that a working as a SaaS solution * in a mass hosting way is not allowed without approval from the * name holder of openTruuls™. * * openTruuls™ 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 * openTruuls™ public License for more details. * * You should have received a copy of the openTruuls™ public License * along with openTruuls™. If not, see <http://www.opentruuls.org/licenses/>. */ package de.forsthaus.webui.security.user; import java.io.Serializable; import java.lang.reflect.InvocationTargetException; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.springframework.security.core.context.SecurityContextHolder; import org.zkoss.util.resource.Labels; import org.zkoss.zk.ui.Component; import org.zkoss.zk.ui.WrongValueException; import org.zkoss.zk.ui.event.Event; import org.zkoss.zk.ui.event.EventListener; import org.zkoss.zkplus.databind.AnnotateDataBinder; import org.zkoss.zul.Button; import org.zkoss.zul.Textbox; import org.zkoss.zul.Window; import de.forsthaus.backend.model.SecUser; import de.forsthaus.backend.service.UserService; import de.forsthaus.backend.util.ZksampleBeanUtils; import de.forsthaus.policy.model.UserImpl; import de.forsthaus.webui.util.ButtonStatusCtrl; import de.forsthaus.webui.util.GFCBaseCtrl; import de.forsthaus.webui.util.MultiLineMessageBox; import de.forsthaus.webui.util.ZksampleMessageUtils; /** * EN: Controller for the <b>My User Settings</b>.<br> * For checking the re-typed password we use an own local bean Pwd with a * property 'retypePassword' that is filled at start with the users password.<br> * DE: Controller fuer das Modul <b>User Einstellungen</b>. <br> * Um das re-typed Passwort zu pruefen, verwenden wir eine eigene locale Klasse * Pwd deren property 'retypePassword' beim Start gefuellt wird.<br> * <br> * zul-file: /WEB-INF/pages/security/mySettings/mySettings.zul.<br> * <br> * * * @author Stephan Gerth */ public class MyUserSettingsCtrl extends GFCBaseCtrl implements Serializable { private static final long serialVersionUID = 1L; private transient static final Logger logger = Logger.getLogger(MyUserSettingsCtrl.class); /* * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ * All the components that are defined here and have a corresponding * component with the same 'id' in the zul-file are getting autowired by our * 'extends GFCBaseCtrl' GenericForwardComposer. * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ protected Window windowMyUserSettings; // autowired protected Textbox txtb_User_Loginname; // autowired protected Textbox txtb_User_Password; // autowired protected Textbox txtb_User_Password_Retype; // autowired protected Textbox txtb_User_Lastname; // autowired protected Textbox txtb_User_Firstname; // autowired protected Textbox txtb_User_Email; // autowired // Button controller for the CRUD buttons private final String btnCtroller_ClassPrefix = "btn_MyUserSettings_"; private ButtonStatusCtrl btnCtrlMyUserSettings; protected Button btnNew; // autowire protected Button btnEdit; // autowire protected Button btnDelete; // autowire protected Button btnSave; // autowire protected Button btnCancel; // autowire protected Button btnClose; // autowire // ServiceDAOs / Domain Classes private UserService userService; // databinding protected transient AnnotateDataBinder binder; private SecUser selectedUser; // a copy from the selected Object. Used for cancel an action. private SecUser originalUser; // internal class for holding the retyped-password private Pwd pwd; /** * default constructor.<br> */ public MyUserSettingsCtrl() { super(); } @Override public void doAfterCompose(Component window) throws Exception { super.doAfterCompose(window); /** * Set an 'alias' for this composer name in the zul file for access.<br> * Set the parameter 'recurse' to 'false' to avoid problems with * managing more than one zul-file in one page. Otherwise it would be * overridden and can ends in curious error messages. */ self.setAttribute("controller", this, false); // create the Button Controller. Disable not used buttons during working btnNew.detach(); btnDelete.detach(); btnCtrlMyUserSettings = new ButtonStatusCtrl(getUserWorkspace(), btnCtroller_ClassPrefix, true, null, btnEdit, null, btnSave, btnCancel, btnClose); btnCtrlMyUserSettings.setSecurityActive(false); // init the buttons on editMode btnCtrlMyUserSettings.setInitEdit(); } // +++++++++++++++++++++++++++++++++++++++++++++++++ // // +++++++++++++++ Component Events ++++++++++++++++ // // +++++++++++++++++++++++++++++++++++++++++++++++++ // /** * Automatically called method from zk. * * @param event * @throws Exception */ public void onCreate$windowMyUserSettings(Event event) throws Exception { // logger.debug("--> " + event.toString()); binder = (AnnotateDataBinder) event.getTarget().getAttribute("binder", true); // Get the logged in user SecUser anUser = ((UserImpl) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getSecUser(); if (anUser != null) { setUser(anUser); setSelectedUser(anUser); // set the retyped password in an special created bean for // databinding Pwd aPwd = new Pwd(); aPwd.setRetypePassword(anUser.getUsrPassword()); setPwd(aPwd); } binder.loadAll(); windowMyUserSettings.doModal(); } /** * When the "help" button is clicked. * * @param event * @throws InterruptedException */ public void onClick$btnHelp(Event event) throws InterruptedException { doHelp(event); } /** * When the "save" button is clicked. * * @param event * @throws InterruptedException */ public void onClick$btnSave(Event event) throws InterruptedException { doSave(event); } /** * When the "cancel" button is clicked. * * @param event * @throws InterruptedException */ public void onClick$btnEdit(Event event) throws InterruptedException { doEdit(event); } /** * When the "cancel" button is clicked. * * @param event * @throws InterruptedException */ public void onClick$btnCancel(Event event) throws InterruptedException { doCancel(event); } /** * When the "close" button is clicked. * * @param event * @throws InterruptedException */ public void onClick$btnClose(Event event) throws InterruptedException { doClose(event); } // +++++++++++++++++++++++++++++++++++++++++++++++++ // // +++++++++++++++++ Business Logic ++++++++++++++++ // // +++++++++++++++++++++++++++++++++++++++++++++++++ // /** * 1. Cancel the current action.<br> * 2. Reset the values to its origin.<br> * 3. Set UI components back to readOnly/disable mode.<br> * 4. Set the buttons in edit mode.<br> * * @param event * @throws InterruptedException */ private void doCancel(Event event) throws InterruptedException { // check first, if the tabs are created if (getBinder() != null) { // reset to the original object doResetToInitValues(); // additionally we must manually set the reTyped Password to its // original getPwd().setRetypePassword(getSelectedUser().getUsrPassword()); getBinder().loadAll(); // set editable Mode doReadOnlyMode(true); btnCtrlMyUserSettings.setInitEdit(); } btnCtrlMyUserSettings.setInitEdit(); } /** * Saves all involved Beans to the DB. * * @param event * @throws InterruptedException */ private void doSave(Event event) throws InterruptedException { getBinder().saveAll(); // check if Pasword equals ReTyped password if (!StringUtils.equals(getSelectedUser().getUsrPassword(), getPwd().getRetypePassword())) { throw new WrongValueException(txtb_User_Password_Retype, Labels.getLabel("message.error.RetypedPasswordMustBeSame")); } try { // save it getUserService().saveOrUpdate(getSelectedUser()); // if saving is successfully than actualize the beans as origins. doStoreInitValues(); } catch (Exception e) { ZksampleMessageUtils.showErrorMessage(e.getMessage()); } finally { btnCtrlMyUserSettings.setInitEdit(); doReadOnlyMode(true); } btnCtrlMyUserSettings.setInitEdit(); } /** * Opens the help screen for the current module. * * @param event * @throws InterruptedException */ private void doHelp(Event event) throws InterruptedException { ZksampleMessageUtils.doShowNotImplementedMessage(); // we stop the propagation of the event, because zk will call ALL events // with the same name in the namespace and 'btnHelp' is a standard // button in this application and can often appears. // Events.getRealOrigin((ForwardEvent) event).stopPropagation(); event.stopPropagation(); } /** * Sets all UI-components to writable-mode. Sets the buttons to edit-Mode. * Checks first, if the NEEDED TABS with its contents are created. If not, * than create it by simulate an onSelect() with calling Events.sendEvent() * * @param event * @throws InterruptedException * @throws InterruptedException */ private void doEdit(Event event) throws InterruptedException { doStoreInitValues(); doReadOnlyMode(false); btnCtrlMyUserSettings.setBtnStatus_Edit(); } /** * When the Tab/Window is closed.<br> * We check if their are unsaved data by comparing the selectedBean's data * with the originalBean's data. * * @param event * @throws InterruptedException */ public void doClose(Event event) throws InterruptedException { if (isDataChanged()) { // Show a confirm box final String msg = Labels.getLabel("message.Information.SaveModifiedDataYesNo"); final String title = Labels.getLabel("message.Information"); MultiLineMessageBox.doSetTemplate(); if (MultiLineMessageBox.show(msg, title, MultiLineMessageBox.YES | MultiLineMessageBox.NO | MultiLineMessageBox.CANCEL, MultiLineMessageBox.QUESTION, true, new EventListener() { @Override public void onEvent(Event evt) { switch (((Integer) evt.getData()).intValue()) { case MultiLineMessageBox.YES: try { doSave(evt); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } windowMyUserSettings.onClose(); case MultiLineMessageBox.NO: windowMyUserSettings.onClose(); case MultiLineMessageBox.CANCEL: break; } } } ) == MultiLineMessageBox.YES) { } event.stopPropagation(); } else { windowMyUserSettings.onClose(); } } /** * Checks, if data are changed since the last call of <br> * the involved controllers doStoreInitValues() . <br> * Works by comparing the properties of the beans. * * @return true, if data are changed, otherwise false */ private boolean isDataChanged() { boolean result = true; SecUser selObject = getSelectedUser(); SecUser origObject = getOriginalUser(); if (selObject == null || origObject == null) { result = false; } else { // invert boolean result = !org.apache.commons.lang.builder.EqualsBuilder.reflectionEquals(selObject, origObject); } return result; } // +++++++++++++++++++++++++++++++++++++++++++++++++ // // ++++++++++++++++++++ Helpers ++++++++++++++++++++ // // +++++++++++++++++++++++++++++++++++++++++++++++++ // /** * Set all components in readOnly/disabled modus. * * true = all components are readOnly or disabled.<br> * false = all components are accessable.<br> * * @param b */ public void doReadOnlyMode(boolean b) { txtb_User_Loginname.setReadonly(b); txtb_User_Password.setReadonly(b); txtb_User_Password_Retype.setReadonly(b); txtb_User_Firstname.setReadonly(b); txtb_User_Lastname.setReadonly(b); txtb_User_Email.setReadonly(b); } /** * Saves the selected object's current properties. We can get them back if a * modification is canceled. * * @throws InterruptedException * * @see doResetToInitValues() */ public void doStoreInitValues() throws InterruptedException { if (getSelectedUser() != null) { try { setOriginalUser((SecUser) ZksampleBeanUtils.cloneBean(getSelectedUser())); } catch (IllegalAccessException e) { ZksampleMessageUtils.showErrorMessage(e.getMessage()); } catch (InstantiationException e) { ZksampleMessageUtils.showErrorMessage(e.getMessage()); } catch (InvocationTargetException e) { ZksampleMessageUtils.showErrorMessage(e.getMessage()); } catch (NoSuchMethodException e) { ZksampleMessageUtils.showErrorMessage(e.getMessage()); } } } /** * Reset the selected object to its origin property values. * * @throws InterruptedException * * @see doStoreInitValues() * */ public void doResetToInitValues() throws InterruptedException { if (getOriginalUser() != null) { try { setSelectedUser((SecUser) ZksampleBeanUtils.cloneBean(getOriginalUser())); // TODO Bug in DataBinder?? windowMyUserSettings.invalidate(); } catch (IllegalAccessException e) { ZksampleMessageUtils.showErrorMessage(e.getMessage()); } catch (InstantiationException e) { ZksampleMessageUtils.showErrorMessage(e.getMessage()); } catch (InvocationTargetException e) { ZksampleMessageUtils.showErrorMessage(e.getMessage()); } catch (NoSuchMethodException e) { ZksampleMessageUtils.showErrorMessage(e.getMessage()); } } } // +++++++++++++++++++++++++++++++++++++++++++++++++ // // ++++++++++++++++ Setter/Getter ++++++++++++++++++ // // +++++++++++++++++++++++++++++++++++++++++++++++++ // public void setUser(SecUser anUser) { setSelectedUser(anUser); } public SecUser getUser() { return getSelectedUser(); } public void setSelectedUser(SecUser selectedUser) { this.selectedUser = selectedUser; } public SecUser getSelectedUser() { return selectedUser; } public void setOriginalUser(SecUser originalUser) { this.originalUser = originalUser; } public SecUser getOriginalUser() { return originalUser; } public AnnotateDataBinder getBinder() { return binder; } public void setBinder(AnnotateDataBinder binder) { this.binder = binder; } public void setUserService(UserService userService) { this.userService = userService; } public UserService getUserService() { return userService; } /** * EN: Internal Class for holding the re-typed password for checking against * the users original password.<br> * DE: Interne Klasse die das re-typed Passwort haelt, das gegen des Users * Passwort geprueft wird.<br> * * @author sge * */ final public class Pwd implements Serializable { private static final long serialVersionUID = 1L; private String retypePassword; public void setRetypePassword(String retypePassword) { this.retypePassword = retypePassword; } public String getRetypePassword() { return retypePassword; } } public Pwd getPwd() { return pwd; } public void setPwd(Pwd pwd) { this.pwd = pwd; } }