ZK MVVM Form Binding CRUD with Spring and Hibernate - Part 9

Bug Fixing.

        


In the previous part 8, we have seen how we can change the theme by each user. Now it is the time to fix some bugs.

Bug 1:
Bug on Message box confirmation on delete. When you try to delete user from the list on clicking delete button, we are asking the confirmation. In this confirmation, on clicking of ok , we should ask for the second final confirmation. But even system asking the second confirmation even when we click cancel for the first confirmation. Now let us change this.

Step 1:
I am just
going follow this forum post to solve the message box bug.

Let us create  a new package under zkexample and name as “utilities” and create the ConfirmResponse interface as said in the zk forum.

image

package zkexample.utilities;

public interface ConfirmResponse {
public void onConfirmClick(String code, int button);
}




Next we will create another class called “MyLib” as follows
image




package zkexample.utilities;

import java.util.HashMap;
import java.util.Map;

import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zul.Messagebox;
import org.zkoss.zul.Messagebox.ClickEvent;

public final class MyLib {

@SuppressWarnings({ "unchecked", "rawtypes" })
public static void confirm(final String code, final String msg,
final String title, final ConfirmResponse cnf) {

Map params = new HashMap();
params.put("width", 500);

Messagebox.Button[] messageBoxButtons;
messageBoxButtons = new Messagebox.Button[] { Messagebox.Button.YES,
Messagebox.Button.NO };

Messagebox.show(msg, "Confirmation", messageBoxButtons, null,
Messagebox.QUESTION, null, new EventListener<ClickEvent>() {
@Override
public void onEvent(ClickEvent e) throws Exception {
if (null == cnf) {
return;
}
if (Messagebox.ON_YES.equals(e.getName())) {
cnf.onConfirmClick(code, Messagebox.YES);
} else if (Messagebox.ON_NO.equals(e.getName())) {
cnf.onConfirmClick(code, Messagebox.NO);
}

}
}, params);
}

}





Step 2:
Now let us change  UserListVM.Java. Let UserListVM implements ConfirmResponse and we will change the OnDelete method. Here is the modified UserListVM



package zkexample.zkoss;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import org.zkoss.bind.BindUtils;
import org.zkoss.bind.annotation.AfterCompose;
import org.zkoss.bind.annotation.BindingParam;
import org.zkoss.bind.annotation.Command;
import org.zkoss.bind.annotation.ContextParam;
import org.zkoss.bind.annotation.ContextType;
import org.zkoss.bind.annotation.ExecutionArgParam;
import org.zkoss.bind.annotation.NotifyChange;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.Executions;
import org.zkoss.zk.ui.select.Selectors;
import org.zkoss.zk.ui.select.annotation.WireVariable;
import org.zkoss.zkplus.spring.SpringUtil;
import org.zkoss.zul.Center;
import org.zkoss.zul.Messagebox;

import zkexample.domain.UserProfile;
import zkexample.service.CRUDService;
import zkexample.utilities.ConfirmResponse;
import zkexample.utilities.MyLib;

public class UserListVM implements ConfirmResponse {

private Center centerArea;
private DataFilter dataFilter = new DataFilter();

@WireVariable
private CRUDService CRUDService;

private UserProfile selectedItem;
private List<UserProfile> allReordsInDB = null;
private List<UserProfile> userList = null;

public UserProfile getSelectedItem() {
return selectedItem;
}

public void setSelectedItem(UserProfile selectedItem) {
this.selectedItem = selectedItem;
}

public DataFilter getDataFilter() {
return dataFilter;
}

public void setDataFilter(DataFilter dataFilter) {
this.dataFilter = dataFilter;
}

@AfterCompose
public void initSetup(@ContextParam(ContextType.VIEW) Component view,
@ExecutionArgParam("centerArea") Center centerArea) {
Selectors.wireComponents(view, this, false);
this.centerArea = centerArea;
CRUDService = (CRUDService) SpringUtil.getBean("CRUDService");
allReordsInDB = CRUDService.getAll(UserProfile.class);
userList = new ArrayList<UserProfile>((allReordsInDB));

}

public List<UserProfile> getDataSet() {
return allReordsInDB;
}

@Command
public void onAddNew() {
final HashMap<String, Object> map = new HashMap<String, Object>();
map.put("selectedRecord", null);
map.put("recordMode", "NEW");
map.put("centerArea", centerArea);
centerArea.getChildren().clear();
Executions.createComponents("UserCRUD.zul", centerArea, map);
}

@Command
public void onEdit(@BindingParam("userRecord") UserProfile userProfile) {

final HashMap<String, Object> map = new HashMap<String, Object>();
map.put("selectedRecord", userProfile);
map.put("recordMode", "EDIT");
map.put("centerArea", centerArea);
centerArea.getChildren().clear();
Executions.createComponents("UserCRUD.zul", centerArea, map);
}

@Command
public void openAsReadOnly(
@BindingParam("userRecord") UserProfile userProfile) {

final HashMap<String, Object> map = new HashMap<String, Object>();
map.put("selectedRecord", userProfile);
map.put("recordMode", "READ");
map.put("centerArea", centerArea);
centerArea.getChildren().clear();
Executions.createComponents("UserCRUD.zul", centerArea, map);
}

@Command
public void onDelete(@BindingParam("userRecord") UserProfile userProfile) {
MyLib.confirm("deleteFirstConfirm", "The Selected practice \""
+ selectedItem.getUserLoginID() + "\" will be deleted.?",
"Confirmation", this);

}

@NotifyChange("dataSet")
@Command
public void doFilter() {
allReordsInDB = new ArrayList<UserProfile>();
;
for (Iterator<UserProfile> i = userList.iterator(); i.hasNext();) {
UserProfile tmp = i.next();
if (tmp.getFirstName().toLowerCase()
.indexOf(dataFilter.getFirstName().toLowerCase()) == 0
&& tmp.getLastName().toLowerCase()
.indexOf(dataFilter.getLastName().toLowerCase()) == 0
&& tmp.getEmail().toLowerCase()
.indexOf(dataFilter.getEmail().toLowerCase()) == 0
&& tmp.getUserLoginID().toLowerCase()
.indexOf(dataFilter.getLoginID().toLowerCase()) == 0) {
allReordsInDB.add(tmp);

}
}

}

@Command
public void Logout() {
Executions.sendRedirect("/j_spring_security_logout");
}

@Override
public void onConfirmClick(String code, int button) {
if (code.equals("deleteFirstConfirm") && button == Messagebox.YES) {
MyLib.confirm(
"deleteSecondConfirm",
"The Selected practice \""
+ selectedItem.getUserLoginID()
+ "\" will be permanently deleted and the action cannot be undone..?",
"Confirmation", this);
}
if (code.equals("deleteSecondConfirm") && button == Messagebox.YES) {

CRUDService.delete(selectedItem);

allReordsInDB.remove(allReordsInDB.indexOf(selectedItem));
BindUtils.postNotifyChange(null, null, UserListVM.this, "dataSet");

}
}

}



Bug 2:
Second is not really a bug, just a small change. After login into application, you can see some flickering happens to change the theme by each user. Now we will avoid this by adding one more zul file called index.zul

First, we will add apache Common library into our project. Open the POM File and add the following dependency.



<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.1</version>
</dependency>

<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.0</version>
</dependency>


First remove the theme.register code from userListVM.Java and also remove the following lines from MainVM.Java


if (_sess.getAttribute("theme") == null) {
String theme = FHSessionUtil.getCurrentUser().getTheme();
if (!theme.equals(Themes.getCurrentTheme())) {
Themes.setTheme(Executions.getCurrent(), FHSessionUtil.getCurrentUser().getTheme());
Executions.sendRedirect(null);
}
_sess.setAttribute("theme", 1);
}


Now let us add the index.zul as shown
image



<zk>
<window apply="org.zkoss.bind.BindComposer"
viewModel="@id('vm')@init('zkexample.zkoss.IndexVM')">
</window>
</zk>



 



package zkexample.zkoss;

import org.zkoss.bind.annotation.AfterCompose;
import org.zkoss.bind.annotation.ContextParam;
import org.zkoss.bind.annotation.ContextType;
import org.zkoss.web.theme.StandardTheme.ThemeOrigin;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.Executions;
import org.zkoss.zul.theme.Themes;

public class IndexVM {

@AfterCompose
public void initSetup(@ContextParam(ContextType.VIEW) Component view) {

Themes.register("bluetheme", ThemeOrigin.FOLDER);
Themes.register("greentheme", ThemeOrigin.FOLDER);
Themes.register("browntheme", ThemeOrigin.FOLDER);
Themes.register("purpletheme", ThemeOrigin.FOLDER);
Themes.register("redtheme", ThemeOrigin.FOLDER);

String theme = FHSessionUtil.getCurrentUser().getTheme();
if (!theme.equals(Themes.getCurrentTheme())) {
Themes.setTheme(Executions.getCurrent(), FHSessionUtil
.getCurrentUser().getTheme());
}

Executions.sendRedirect("main.zul");
}

}



Next in the zkaddon.xml, remove the following line.
<stylesheet href="/css/blueTheme.css" type="text/css" />

Next in the spring-security.xml, change the default target url to index.zul as shown.



<!-- Spring namespace-based configuration -->

<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.1.xsd">

<!-- ====================================================== -->
<!-- For catching the @Secured annotation methods -->
<!-- Tells the Spring Security engine that we will use Spring Security's -->
<!-- pre and post invocation Java annotations (@PreFilter, @PreAuthorize, -->
<!-- @PostFilter, -->
<!-- @PostAuthorize) to secure service layer methods.. -->
<!-- Look in GFCBaseCtrl.java onEvent() method. -->
<!-- ====================================================== -->

<!-- Enable the @Secured annotation to secure service layer methods -->
<global-method-security secured-annotations="enabled" />

<http auto-config="true">

<!-- ====================================================== -->
<!-- If we have our own LoginPage. So we must -->
<!-- tell Spring the name and the place. -->
<!-- In our case we take the same page -->
<!-- for a error message by a failure. -->
<!-- Further the page after a successfully login. -->
<!-- ====================================================== -->
<form-login login-page="/login.zul"
authentication-failure-url="/login.zul?login_error=1"
default-target-url="/index.zul" always-use-default-target="true" />
<intercept-url pattern="/login.zul" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<intercept-url pattern="/*.zul" access="IS_AUTHENTICATED_REMEMBERED" />
</http>

<authentication-manager>
<authentication-provider user-service-ref="myUserDetailsService">

</authentication-provider>
</authentication-manager>

<beans:bean id="myUserDetailsService" class="zkexample.service.MyUserDetailsService" />


</beans:beans>





And also, in the web.xml, change the welcome-file-List as follows
<welcome-file-list>
        <welcome-file>index.zul</welcome-file>
        <welcome-file>index.zhtml</welcome-file>
        <welcome-file>index.html</welcome-file>
        <welcome-file>index.htm</welcome-file>
    </welcome-file-list>

Now you can select the Project and Right click, Select Run as –> Run on Server.

You can download the source here.

In the next Part 10, we will see how we can integrate jquery plugins in ZK Framework.