Sunday, 21 September 2014

ZK upload PDF to server and show in the screen using MVVM–Part 2

In the Part 1, we have seen how to upload the PDF File and show in the same desktop. This example will show you how to show the PDF in the separate tab in the same browser window.


ZK Version : ZK 7.0.3
Project Name : zk7example6

Step 1:
Follow
this post, to create ZK 7 Maven Project.

image
When you create ZK Maven Project, you can see by default index.zul and MyViewModel.Java will be created. We will modify this zul and VM for our example.


Step 2:
Let us modify the index.zul and MyViewModel.java to accept the PDF File from the user and stored in the server directory. And also You can see that there are two buttons to show the PDF ; one is to show PDF File on the same desktop, and the other is to show the same PDF in the separate tab in the same browser.

Index.zul

<zk>
<window apply="org.zkoss.bind.BindComposer"
viewModel="@id('vm')@init('ZKExample6.MyViewModel')">
<label value="You are using: ${desktop.webApp.version}" />
<separator></separator>
<label
value="Example for File upload to the server and display it" />
<separator></separator>
<hbox>
<label value="Upload any PDF File" />
<button label="Upload" upload="true"
onUpload="@command('onUploadPDF',upEvent=event)">
</button>
</hbox>
<button label="Show PDF Option 1" visible="@load(vm.fileuploaded)"
onClick="@command('showPDFOption1')">
</button>
<button label="Show PDF Option 2" visible="@load(vm.fileuploaded)"
onClick="@command('showPDFOption2')">
</button>
</window>
</zk>

ViewModel for our Index.zul file.


package ZKExample6;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Calendar;

import org.zkoss.bind.BindContext;
import org.zkoss.bind.annotation.AfterCompose;
import org.zkoss.bind.annotation.Command;
import org.zkoss.bind.annotation.ContextParam;
import org.zkoss.bind.annotation.ContextType;
import org.zkoss.bind.annotation.NotifyChange;
import org.zkoss.io.Files;
import org.zkoss.util.media.AMedia;
import org.zkoss.util.media.Media;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.Executions;
import org.zkoss.zk.ui.event.UploadEvent;
import org.zkoss.zk.ui.select.Selectors;
import org.zkoss.zk.ui.select.annotation.Wire;
import org.zkoss.zul.Iframe;
import org.zkoss.zul.Messagebox;
import org.zkoss.zul.Window;

public class MyViewModel {

private String filePath;
private boolean fileuploaded = false;
AMedia fileContent;

@Wire("#test")
private Window win;

public AMedia getFileContent() {
return fileContent;
}

public void setFileContent(AMedia fileContent) {
this.fileContent = fileContent;
}

public boolean isFileuploaded() {
return fileuploaded;
}

public void setFileuploaded(boolean fileuploaded) {
this.fileuploaded = fileuploaded;
}

@AfterCompose
public void initSetup(@ContextParam(ContextType.VIEW) Component view) {
Selectors.wireComponents(view, this, false);

}

@Command
@NotifyChange("fileuploaded")
public void onUploadPDF(
@ContextParam(ContextType.BIND_CONTEXT) BindContext ctx)
throws IOException {

UploadEvent upEvent = null;
Object objUploadEvent = ctx.getTriggerEvent();
if (objUploadEvent != null && (objUploadEvent instanceof UploadEvent)) {
upEvent = (UploadEvent) objUploadEvent;
}
if (upEvent != null) {
Media media = upEvent.getMedia();
Calendar now = Calendar.getInstance();
int year = now.get(Calendar.YEAR);
int month = now.get(Calendar.MONTH); // Note: zero based!
int day = now.get(Calendar.DAY_OF_MONTH);
filePath = Executions.getCurrent().getDesktop().getWebApp()
.getRealPath("/");
String yearPath = "\\" + "PDFs" + "\\" + year + "\\" + month + "\\"
+ day + "\\";
filePath = filePath + yearPath;
File baseDir = new File(filePath);
if (!baseDir.exists()) {
baseDir.mkdirs();
}
Files.copy(new File(filePath + media.getName()),
media.getStreamData());
Messagebox.show("File Sucessfully uploaded in the path [ ."
+ filePath + " ]");
fileuploaded = true;
filePath = filePath + media.getName();
}
}

@Command
public void showPDFOption1() throws IOException {
Window win = (Window) Executions.createComponents(
"zkpdfviewer.zul", null, null);
Iframe frame = (Iframe) win.getFellow("reportframe");
File f = new File(this.filePath);
byte[] buffer = new byte[(int) f.length()];
FileInputStream fs = new FileInputStream(f);
fs.read(buffer);
fs.close();

ByteArrayInputStream is = new ByteArrayInputStream(buffer);
AMedia amedia = new AMedia(filePath, "pdf", "application/pdf", is);
frame.setContent(amedia);

}

@Command
public void showPDFOption2() throws IOException {
String URL;
URL = "zkpdfviewer.zul?filepath=";
URL = URL + EncryptionUtil.encode(filePath);
Executions.getCurrent().sendRedirect(URL, "_blank");

}
}

Step 3:
As you can see, we have two buttons to show the uploaded PDF. One option is normal to open on the same screen, and the other one is open the pdf in the separate tab.In the both option, we have used separate ZUL File to view the PDF. Here is the zul file and its corresponding VM.


 <window id="pdfwindow" width="100%" height="100%" title="PDF-Viewer"
border="normal" minimizable="false" mode="modal" maximizable="false"
sclass="mymodal" closable="true" apply="org.zkoss.bind.BindComposer"
viewModel="@id('vm') @init('ZKExample6.ZKPDFViewerVM')">
<iframe height="100%" width="100%" id="reportframe"></iframe>
</window>

View Model

package ZKExample6;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;

import org.zkoss.bind.annotation.AfterCompose;
import org.zkoss.bind.annotation.ContextParam;
import org.zkoss.bind.annotation.ContextType;
import org.zkoss.bind.annotation.QueryParam;
import org.zkoss.util.media.AMedia;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.select.Selectors;
import org.zkoss.zk.ui.select.annotation.Wire;
import org.zkoss.zul.Iframe;

public class ZKPDFViewerVM {

@Wire("#reportframe")
private Iframe iframe;

@AfterCompose
public void initSetup(@ContextParam(ContextType.VIEW) Component view,
@QueryParam("filepath") String filePath) throws Exception {
Selectors.wireComponents(view, this, false);
if (filePath==null)
filePath = "";
if (filePath.isEmpty()==false) {
filePath = EncryptionUtil.decode(filePath);
File f = new File(filePath);
byte[] buffer = new byte[(int) f.length()];
FileInputStream fs = new FileInputStream(f);
fs.read(buffer);
fs.close();
ByteArrayInputStream is = new ByteArrayInputStream(buffer);
AMedia amedia = new AMedia(filePath, "pdf", "application/pdf", is);
iframe.setContent(amedia);
}
}
}

For the second option, actually we are passing the PDF File path from the server as URL and we received this in the VM and then showing the IFrame. For security reasons,  We can encode the URL and then we can decode the URL. That's what the additional static class EncryptionUtil.java does. Here is the code.


package ZKExample6;

import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.KeySpec;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;

import org.apache.commons.codec.binary.Base64;

public class EncryptionUtil {

private static final byte[] SALT = { (byte) 0x21, (byte) 0x21, (byte) 0xF0,
(byte) 0x55, (byte) 0xC3, (byte) 0x9F, (byte) 0x5A, (byte) 0x75 };

private final static int ITERATION_COUNT = 31;

private EncryptionUtil() {
}

public static String encode(String input) {
if (input == null) {
throw new IllegalArgumentException();
}
try {

KeySpec keySpec = new PBEKeySpec(null, SALT, ITERATION_COUNT);
AlgorithmParameterSpec paramSpec = new PBEParameterSpec(SALT,
ITERATION_COUNT);

SecretKey key = SecretKeyFactory.getInstance("PBEWithMD5AndDES")
.generateSecret(keySpec);

Cipher ecipher = Cipher.getInstance(key.getAlgorithm());
ecipher.init(Cipher.ENCRYPT_MODE, key, paramSpec);

byte[] enc = ecipher.doFinal(input.getBytes());

String res = new String(Base64.encodeBase64(enc));
// escapes for url
res = res.replace('+', '-').replace('/', '_').replace("%", "%25")
.replace("\n", "%0A");

return res;

} catch (Exception e) {
}

return "";

}

public static String decode(String token) {
if (token == null) {
return null;
}
try {

String input = token.replace("%0A", "\n").replace("%25", "%")
.replace('_', '/').replace('-', '+');

byte[] dec = Base64.decodeBase64(input.getBytes());

KeySpec keySpec = new PBEKeySpec(null, SALT, ITERATION_COUNT);
AlgorithmParameterSpec paramSpec = new PBEParameterSpec(SALT,
ITERATION_COUNT);

SecretKey key = SecretKeyFactory.getInstance("PBEWithMD5AndDES")
.generateSecret(keySpec);

Cipher dcipher = Cipher.getInstance(key.getAlgorithm());
dcipher.init(Cipher.DECRYPT_MODE, key, paramSpec);

byte[] decoded = dcipher.doFinal(dec);

String result = new String(decoded);
return result;

} catch (Exception e) {
// use logger in production code
e.printStackTrace();
}

return null;
}

}



Here is the complete Project Structure

image
|
Now you can run the index.zul file and you check the output by clicking the two buttons.
You can download the source code
here.

Saturday, 20 September 2014

ZK List Box : How to show particular row in different color in MVVM

In this example, we will see how to change the color based on some conditions.

ZK Version : ZK 7.0.3
Project Name : zk7example5

Step 1:
Follow
this post, to create ZK 7 Maven Project.

Step 2:
Create the Person Bean in the ZKExample5 Package
package ZKExample5;

public class Person {
private String firstName;
private String lastName;
private String email;
private Integer active;

public Person(String firstName, String lastName, String email,Integer active) {
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
this.active = active;
}

public Integer getActive() {
return active;
}

public void setActive(Integer active) {
this.active = active;
}

public String getFirstName() {
return firstName;
}

public void setFirstName(String firstName) {
this.firstName = firstName;
}

public String getLastName() {
return lastName;
}

public void setLastName(String lastName) {
this.lastName = lastName;
}

public String getEmail() {
return email;
}

public void setEmail(String email) {
this.email = email;
}

}


Step 3:
Create the Person ZUL Under the webapp folder as

<window title="Example for ZK MVVM List Box" width="500px"
apply="org.zkoss.bind.BindComposer"
viewModel="@id('vm') @init('ZKExample5.ViewModel.PersonVM')">
<label value="You are using: ${desktop.webApp.version}" />
<separator></separator>
<listbox model="@load(vm.allPersons)" checkmark="true" mold="paging"
pageSize="10" multiple="true"
selectedItems="@bind(vm.selectedPersons)">
<listhead sizable="true">
<listheader label="First Name" sortDirection="ascending"
sort="auto(firstName)" />
<listheader label="Last Name" sort="auto(lastName)" />
<listheader label="Email" sort="auto(email)" />
</listhead>
<template name="model" var="p1">
<listitem>
<listcell label="@load(p1.firstName)" />
<listcell label="@load(p1.lastName)" />
<listcell label="@load(p1.email)" />
</listitem>
</template>
</listbox>

</window>

 


Step 4:
Now let us create the View Model for the above zul file as follows


package ZKExample5.ViewModel;

import java.util.ArrayList;
import java.util.List;

import ZKExample5.Person;

public class PersonVM {
private List<Person> allPersons = new ArrayList<Person>();
private List<Person> selectedPersons;


public List<Person> getSelectedPersons() {
return selectedPersons;
}

public void setSelectedPersons(List<Person> selectedPersons) {
this.selectedPersons = selectedPersons;
}

public List<Person> getAllPersons() {
return allPersons;
}

public void setAllPersons(List<Person> allPersons) {
this.allPersons = allPersons;
}

public PersonVM()
{
allPersons.add(new Person("John", "James", "JohnJames@yahoo.com",1));
allPersons.add(new Person("Taylor", "Harris", "Harris@yahoo.com",0));
allPersons.add(new Person("Allen", "Scott", "Scott@yahoo.com",1));
allPersons.add(new Person("Minna", "Kristeen", "Kristeen@yahoo.com",0));
allPersons.add(new Person("Abel", "Olive", "Olive@yahoo.com",1));
allPersons.add(new Person("Kiley", "Renea", "Renea@yahoo.com",0));
allPersons.add(new Person("Graciela", "Samira", "Samira@yahoo.com",0));
allPersons.add(new Person("Cammy", "Jenelle", "Jenelle@yahoo.com",1));
allPersons.add(new Person("Mattie", "Jerry", "Jerry@yahoo.com",1));
allPersons.add(new Person("Meaghan", "Ozell", "Ozell@yahoo.com",0));
}


}

Step 5:
Now let us create our css file. Create a folder called “css” in the webapp folder and create a css file namely style.css as shown
image


Here is the content of the CSS File



@CHARSET "ISO-8859-1";

.inactive .z-listcell-content {
color: #FF9900;
text-decoration: underline;
text-decoration: line-through;
}




Step 6:
Now refer the above css file in the person.zul and As you can see, we have a property called active which basically contains 1 or 0. Now we will show persons which is inactive (1) in different color. So change the zul file as follows
 


<window title="Example for ZK MVVM List Box" width="500px"
apply="org.zkoss.bind.BindComposer"
viewModel="@id('vm') @init('ZKExample5.ViewModel.PersonVM')">
<style src="/css/style.css" />
<label value="You are using: ${desktop.webApp.version}" />
<separator></separator>
<listbox model="@load(vm.allPersons)" checkmark="true" mold="paging"
pageSize="10" multiple="true"
selectedItems="@bind(vm.selectedPersons)">
<listhead sizable="true">
<listheader label="First Name" sortDirection="ascending"
sort="auto(firstName)" />
<listheader label="Last Name" sort="auto(lastName)" />
<listheader label="Email" sort="auto(email)" />
<listheader label="Active" sort="auto(active)" />
</listhead>
<template name="model" var="p1">
<listitem sclass="@load(p1.active eq 1 ?'inactive':'')">
<listcell label="@load(p1.firstName)" />
<listcell label="@load(p1.lastName)" />
<listcell label="@load(p1.email)" />
<listcell label="@load(p1.active)" />
</listitem>
</template>
</listbox>

</window>


Now you can run the person.zul . Here is the output.


image

ZK MVVM List Box Select All and Unselect all Records

I have a list box with multiple selection allowed and paging. Actually it means I have 'select all' checkbox in list box header, which allows me select all entries that shown on the current page.

Problem statement: I did not find a way how to catch events from 'select all' checkbox. Actually, I need select all entries (on all pages and not on displayed page!)  when 'select all' checked. And deselect all entries on all pages when 'select all' unchecked.
 
Since 6.5.5, The Select all checkbox on listheader now support onCheckSelectAll event that can determine whether it is checked or not.
ZK Reference


Note: Select all checkbox in list header is only available if ROD is false.

ZK Version : ZK 7.0.3
Project Name : zk7example4

Step 1:
Follow
this post, to create ZK 7 Maven Project.

 

image

Step 2:
Create the Person Bean in the ZKExample4 Package

package ZKExample4;

public class Person {
private String firstName;
private String lastName;
private String email;

public Person(String firstName, String lastName, String email) {
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
}

public String getFirstName() {
return firstName;
}

public void setFirstName(String firstName) {
this.firstName = firstName;
}

public String getLastName() {
return lastName;
}

public void setLastName(String lastName) {
this.lastName = lastName;
}

public String getEmail() {
return email;
}

public void setEmail(String email) {
this.email = email;
}

}


Step 3:
Create the Person ZUL Under the webapp folder as

<window title="Example for ZK MVVM List Box" width="500px"
apply="org.zkoss.bind.BindComposer"
viewModel="@id('vm') @init('ZKExample4.ViewModel.PersonVM')">
<label value="You are using: ${desktop.webApp.version}" />
<separator></separator>
<listbox model="@load(vm.allPersons)" checkmark="true" mold="paging"
pageSize="4" multiple="true"
onCheckSelectAll="@command('onSelectAll')"
selectedItems="@bind(vm.selectedPersons)">
<listhead sizable="true">
<listheader label="First Name" sortDirection="ascending"
sort="auto(firstName)" />
<listheader label="Last Name" sort="auto(lastName)" />
<listheader label="Email" sort="auto(email)" />
</listhead>
<template name="model" var="p1">
<listitem>
<listcell label="@load(p1.firstName)" />
<listcell label="@load(p1.lastName)" />
<listcell label="@load(p1.email)" />
</listitem>
</template>
</listbox>
<label value="Total Selected" />
<separator></separator>
<label value="@load(vm.selectedPersons.size())" />
</window>

Step 4:
Now let us create the View Model for the above zul file as follows

package ZKExample4.ViewModel;

import java.util.ArrayList;
import java.util.List;

import org.zkoss.bind.BindUtils;
import org.zkoss.bind.annotation.Command;
import org.zkoss.bind.annotation.ContextParam;
import org.zkoss.bind.annotation.ContextType;
import org.zkoss.zk.ui.event.CheckEvent;

import ZKExample4.Person;

public class PersonVM {
private List<Person> allPersons = new ArrayList<Person>();
private List<Person> selectedPersons;


public List<Person> getSelectedPersons() {
return selectedPersons;
}

public void setSelectedPersons(List<Person> selectedPersons) {
this.selectedPersons = selectedPersons;
}

public List<Person> getAllPersons() {
return allPersons;
}

public void setAllPersons(List<Person> allPersons) {
this.allPersons = allPersons;
}

public PersonVM()
{
allPersons.add(new Person("John", "James", "JohnJames@yahoo.com"));
allPersons.add(new Person("Taylor", "Harris", "Harris@yahoo.com"));
allPersons.add(new Person("Allen", "Scott", "Scott@yahoo.com"));
allPersons.add(new Person("Minna", "Kristeen", "Kristeen@yahoo.com"));
allPersons.add(new Person("Abel", "Olive", "Olive@yahoo.com"));
allPersons.add(new Person("Kiley", "Renea", "Renea@yahoo.com"));
allPersons.add(new Person("Graciela", "Samira", "Samira@yahoo.com"));
allPersons.add(new Person("Cammy", "Jenelle", "Jenelle@yahoo.com"));
allPersons.add(new Person("Mattie", "Jerry", "Jerry@yahoo.com"));
allPersons.add(new Person("Meaghan", "Ozell", "Ozell@yahoo.com"));
allPersons.add(new Person("Gladys", "Whitley", "Whitley@yahoo.com"));
allPersons.add(new Person("Yuki", "Ligia", "Ligia@yahoo.com"));
allPersons.add(new Person("Chanel", "Erinn", "Erinn@yahoo.com"));
allPersons.add(new Person("Wilda", "Noah", "Noah@yahoo.com"));
allPersons.add(new Person("Rolland", "Gail", "Gail@yahoo.com"));
allPersons.add(new Person("Bok", "Mitzie", "Mitzie@yahoo.com"));
}

@Command
public void onSelectAll(
@ContextParam(ContextType.TRIGGER_EVENT) CheckEvent e) {
this.selectedPersons = new ArrayList<Person>();
if (e.isChecked())
selectedPersons.addAll(allPersons);
BindUtils.postNotifyChange(null, null, this, "selectedPersons");
}
}


Here is the Complete Project Structure

image

Now you can select the person.zul file and run using tomcat. If you select the check box in the header, you can see that all the persons are selected not only in the current page

image

You can download the source here