Archive for the ‘- ZK framework’ Category.

How to create a Captcha in zk ce version?

Creating an own Captcha component while it’s not in the zk community version.

As i work on the ‘forgotten password?’ module in openTruuls™ i would use a Captcha component for the user verification and i’m wondering that such a component is not in the zk community version. So openTruuls™ will be opensourced i need a Captcha component that developers can using without registering for a personal or commercial zk version.

After a few searching in the zk forum and the WWW i became a hint from Maik, the developer behind the jease cms ( www.jease.org ) to using the simpleCaptcha framework.

Argh, the biggest problem was to find a repository where a not corupted  version is downloading via the maven2 build system. And let me talk that i’m do it at last by a manual downloading in the linux shell on our web server because i don’t find a runing version.

Okay, after done this, the result is a little Captcha Controller who creates the Captcha which we can call in a static way. In the forgottenPassword Controller we use this Captcha and get the image from it which we assign to a zk image.

pieces of the zul-template

    .  .  .
								<!-- Captcha / Captcha -->
								<row>
									<space width="0" />
									<hbox>

										<image id="img_Captcha" />

										<toolbarbutton id="btnReCaptcha"
											image="/images/icons/sync_16x16.gif"
											tooltiptext="${c:l('common.ReCaptcha')}" />
									</hbox>
								</row>
   . . .


The complete dialog should looks like in this picture:

ForgottenPasswordController
ForgottenPasswordController

the FDCaptchaUtils.java


/**
 * EN: Utility class for creating a CAPTCHA.<br>
 * Captcha can be direct loaded into a org.zkoss.zul.Image<br>
 * DE: Hilfsklasse zur Erzeugung eines CAPTCHA.<br>
 * Captcha kann direkt in ein org.zkoss.zul.Image eingelesen werden.
 *
 * <pre>
 * Image img = new org.zkoss.zul.Image();
 * img.setContent(CaptchaUtils.getCaptcha().getImage());
 *
 * String verifyStr = captcha.getAnswer();
 * </pre>
 *
 * @author Stephan Gerth
 */
public class FDCaptchaUtils {

	public FDCaptchaUtils() {
	}

	/**
	 * Create a 5 digits captcha.
	 *
	 * @return
	 */
	public static Captcha getCaptcha() {

		Captcha captcha = new Captcha.Builder(170, 50).addText(new ColoredEdgesWordRenderer()).addNoise().addBackground(new GradiatedBackgroundProducer()).addBorder().build();

		return captcha;
	}

}


In the forgotten password controller we create the Captcha and insert it in the zk Image and handles the verify logic.

The needed methods in the controller code looks like this:

pieces of the ForgottenPassword controller

   . . .
   private Captcha captcha; // + getter/setter
   . . .

/**
 * Do a re-Captcha.<br>
 *
 * @param event
 */
private void doReCaptcha(Event event) {
	// init: disable the send password button
	btnReset.setDisabled(true);

	setCaptcha(FDCaptchaUtils.getCaptcha());
	img_Captcha.setContent(getCaptcha().getImage());
}

/**
 * 1. Checks if the email address is entered.<br>
 * 2. Verify the created captcha digits against the users input from a textbox.<br>
 * 3. Enable/disable the 'reset password' button.<br>
 *
 * @param event
 */
private void doVerifyCaptcha(Event event) {

     // init: disable the reset password button
     btnReset.setDisabled(true);

     // check if the tenant ID is entered
     if (StringUtils.isEmpty(longb_TenantID.getValue().toString().trim())) {
       	 throw new WrongValueException(longb_TenantID, Labels.getLabel("message.Error.CannotBeEmpty"));
     }

     // check if the email address is entered
	if (StringUtils.isEmpty(txtb_EmailAddress.getValue())) {
	    throw new WrongValueException(txtb_EmailAddress, Labels.getLabel("message.Error.CannotBeEmpty"));
	}

	// check if the captcha is verified correctly
	if (StringUtils.equals(txtb_VerifyCaptcha.getValue(), getCaptcha().getAnswer())) {
            btnReset.setDisabled(false);
	}
     }


Have fun with it.

Stephan Gerth

Dipl.rer.pol.


PS: Help to prevent the global warming by writing cool software

10. Web Monday in Magdeburg (11.10.2010)

WebMonday in Magdeburg

10. WebMonday in Magdeburg

On Monday i was speeking in Magdeburg on the WebMonday event about the zk framework.

It’s a nice event that take place every second monday in a month in many bigger cities worldwide. Here you can follow the speeches and meet some other guys who are interesting in Web Development.

This monday we have about 4 lectures and all speakers have only 15 minutes time for presenting their lecture and 15 minutes for questions and answers about their theme. I failed. It’s not possible to talk about zk in 15 minutes. I need 10 minutes more and i have luck. No one shoot me.

10. Web Monday

nice living room atmosphere

    Themes

1. Suggy ( all guys from suggy )
2. InfoVis & OpenData ( Gregor Aisch )
3. Template Toolkit 2 ( Alexander Dahl )
4. ZK Ajax Web Framework ( Stephan Gerth )

For all visitors who wants to know more about the webMondays in Magdeburg follow these link.

How to create a MessageSystem with the zk framework ?

A simple messageBarController that works with the new zk5 EventQueues mechanism.

In this article we will create a messaging system which is visually placed in the statusBar. We will call it messageBar and we add it as a Window component left before the statusBar window component as we explained in this previous post.

The ready implemented component are looks like this picture with only two icons in it. The red mail icon is for showing the message. This icon is blinking if there comes new messages in and the message reader is not opened (or if you uncomment a few lines in code it will popUp if a new message come in) . The right next icon is for opening a little window for writing a message text who can be send to all users.

Message Bar component

Message Bar component

pieces of the zul-template

.  .  .
		<!-- STATUS BAR AREA -->
			<south id="south" border="none" height="22px"
				splittable="false">

				<div id="divSouth" align="left"
					style="float: left; padding: 0px" width="100%">

					<borderlayout width="100%" height="22px">

						<west border="none" width="50px">
							<!-- The MessageBar. Comps are created in the Controller -->
							<window id="winMessageBar"
								apply="${messageBarCtrl}" border="none" width="50px"
								height="22px" />
						</west>

						<center border="none">
							<!-- The StatusBar. Comps are created in the Controller -->
							<window id="winStatusBar"
								apply="${statusBarCtrl}" border="none" width="100%"
								height="22px" />
						</center>

					</borderlayout>

				</div>

			</south>
.  .  .

The messageBar controller creates the two icons with their event Listeners and the global Listener for the messaging system. If you whish that an incoming message will popup self than you can uncomment the involved lines in the afterCompose method.

MessageBarCtrl.java

/**
 * =======================================================================<br>
 * MessageBarController. <br>
 * =======================================================================<br>
 * Works with the EventQueues mechanism of zk 5.x. ALl needed components are
 * created in this class. In the zul-template declare only this controller with
 * 'apply' to a winMessageBar window component.<br>
 * This MessageBarController is for sending and receiving messages from other
 * users.<br>
 * 
 * The message text we do input with a special helper window that is called
 * InputMessageTextBox.java
 * 
 * <pre>
 * < borderlayout >
 *   . . .
 *    < !-- STATUS BAR AREA -- >
 *    < south id="south" border="none" margins="1,0,0,0"
 * 		height="20px" splittable="false" flex="true" >
 * 	      < div id="divSouth" >
 * 
 *          < !-- The MessageBar. Comps are created in the Controller -- >
 *          < window id="winMessageBar" apply="${messageBarCtrl}"
 *                   border="none" width="100%" height="100%" />
 *          < !-- The StatusBar. Comps are created in the Controller -- >
 *          < window id="winStatusBar" apply="${statusBarCtrl}"
 *                   border="none" width="100%" height="100%" />
 *        < /div >
 *    < /south >
 *  < /borderlayout >
 * </pre>
 * 
 * call for the message system:
 * 
 * <pre>
 * EventQueues.lookup("userNameEventQueue", EventQueues.APPLICATION, true).publish(new Event("onChangeSelectedObject", null, "new Value"));
 * </pre>
 * 
 * 
 * Spring bean declaration:
 * 
 * <pre>
 * < !-- MessageBarCtrl -->
 * < bean id="messageBarCtrl" class="de.forsthaus.webui.util.MessageBarCtrl"
 *    scope="prototype">
 * < /bean>
 * </pre>
 * 
 * since: zk 5.0.0
 * 
 * @author sgerth
 * 
 */
public class MessageBarCtrl extends GenericForwardComposer implements Serializable {

	private static final long serialVersionUID = 1L;
	/*
	 * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	 * 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 winMessageBar; // autowired

	// Indicator column for message buttons
	private Column statusBarMessageIndicator;
	private Toolbarbutton btnOpenMsg;
	private Toolbarbutton btnSendMsg;

	private Window msgWindow = null;
	private String msg = "";
	private String userName;

	/**
	 * Default constructor.
	 */
	public MessageBarCtrl() {
		super();
	}

	@Override
	public void doAfterCompose(Component window) throws Exception {
		super.doAfterCompose(window);

		try {
			userName = ((UserImpl) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUsername();
		} catch (Exception e) {
			e.printStackTrace();
		}

		// Listener for incoming messages ( scope=APPLICATION )
		EventQueues.lookup("testEventQueue", EventQueues.APPLICATION, true).subscribe(new EventListener() {

			@Override
			public void onEvent(Event event) throws Exception {
				final String msg = (String) event.getData();

				// Check if empty, than do not show incoming message
				if (StringUtils.isEmpty(msg)) {
					return;
				}

				setMsg(msg);

				if (msgWindow == null) {

					/**
					 * If you whish to popup the incoming message than uncomment
					 * these lines.
					 */
					// getMsgWindow();
					// ((Textbox)
					// getMsgWindow().getFellow("tb")).setValue(getMsg());
					MessageBarCtrl.this.btnOpenMsg.setImage("/images/icons/incoming_message1_16x16.gif");
				} else {
					((Textbox) getMsgWindow().getFellow("tb")).setValue(getMsg());
				}
			}
		});

	}

	/**
	 * Automatically called method from zk.
	 * 
	 * @param event
	 */
	public void onCreate$winMessageBar(Event event) {

		final Grid grid = new Grid();
		grid.setHeight("100%");
		grid.setWidth("50px");
		grid.setParent(this.winMessageBar);

		final Columns columns = new Columns();
		columns.setSizable(false);
		columns.setParent(grid);

		// Column for the Message buttons
		this.statusBarMessageIndicator = new Column();
		this.statusBarMessageIndicator.setWidth("50px");
		this.statusBarMessageIndicator.setStyle("background-color: #D6DCDE; padding: 0px");
		this.statusBarMessageIndicator.setParent(columns);
		Div div = new Div();
		div.setStyle("padding: 1px;");
		div.setParent(statusBarMessageIndicator);

		// open message button
		this.btnOpenMsg = new Toolbarbutton();
		this.btnOpenMsg.setWidth("20px");
		this.btnOpenMsg.setHeight("20px");
		this.btnOpenMsg.setImage("/images/icons/message2_16x16.gif");
		this.btnOpenMsg.setTooltiptext(Labels.getLabel("common.Message.Open"));
		this.btnOpenMsg.setParent(div);
		this.btnOpenMsg.addEventListener("onClick", new EventListener() {

			@Override
			public void onEvent(Event event) throws Exception {
				// 1. Reset to normal image
				btnOpenMsg.setImage("/images/icons/message2_16x16.gif");
				// 2. open the message window
				Window win = getMsgWindow();
				Textbox t = (Textbox) win.getFellow("tb");
				t.setText(getMsg());
				// Clients.scrollIntoView(t);

			}
		});

		// send message button
		this.btnSendMsg = new Toolbarbutton();
		this.btnSendMsg.setWidth("20px");
		this.btnSendMsg.setHeight("20px");
		this.btnSendMsg.setImage("/images/icons/message1_16x16.gif");
		this.btnSendMsg.setTooltiptext(Labels.getLabel("common.Message.Send"));
		this.btnSendMsg.setParent(div);
		this.btnSendMsg.addEventListener("onClick", new EventListener() {

			@Override
			public void onEvent(Event event) throws Exception {
				// open a box for inserting the message
				Window win = (Window) Path.getComponent("/outerIndexWindow");
				final String str = InputMessageTextBox.show(win);
				EventQueues.lookup("testEventQueue", EventQueues.APPLICATION, true).publish(new Event("onTestEventQueue", null, str));
			}
		});

	}

	// +++++++++++++++++++++++++++++++++++++++++++++++++ //
	// ++++++++++++++++ Setter/Getter ++++++++++++++++++ //
	// +++++++++++++++++++++++++++++++++++++++++++++++++ //

	public void setMsg(String msg) {
		this.msg = this.msg + "\n" + msg;
	}

	public String getMsg() {
		return msg;
	}

	public void setMsgWindow(Window msgWindow) {
		this.msgWindow = msgWindow;
	}

	public Window getMsgWindow() {

		if (msgWindow == null) {
			msgWindow = new Window();
			msgWindow.setId("msgWindow");
			msgWindow.setTitle("Messages");
			msgWindow.setSizable(true);
			msgWindow.setClosable(true);
			msgWindow.setWidth("400px");
			msgWindow.setHeight("250px");
			msgWindow.setParent(winMessageBar);
			msgWindow.addEventListener("onClose", new EventListener() {

				@Override
				public void onEvent(Event event) throws Exception {
					msgWindow.detach();
					msgWindow = null;
				}
			});
			msgWindow.setPosition("bottom, left");
			Textbox tb = new Textbox();
			tb.setId("tb");
			tb.setMultiline(true);
			tb.setRows(10);
			tb.setReadonly(true);
			tb.setHeight("100%");
			tb.setWidth("98%");
			tb.setParent(msgWindow);

			msgWindow.doOverlapped();

		}

		return msgWindow;
	}
}

If you click on the left mail icon a little window comes up and shows all messages that comes in since the user was logged in.

window for showing the messages

window for showing the messages

After clicking on the right icon there comes a window up for inserting the message text to send.

window for writing and sending a message

window for showing the messages

The code for the InputMessageTextBox looks like this:

InputMessageTextBox.java

/**
 * This class creates a modal window as a dialog in which the user <br>
 * can input some text. By onClosing with <RETURN> or Button <send> this
 * InputConfirmBox can return the message as a String value if not empty. <br>
 * In this case the returnValue is the same as the inputValue.<br>
 * 
 * @author bbruhns
 * @author sgerth
 */
public class InputMessageTextBox extends Window {

	private static final long serialVersionUID = 8109634704496621100L;
	private static final Logger logger = Logger.getLogger(InputMessageTextBox.class);

	private final Textbox textbox;
	private String msg = "";
	private String userName;

	/**
	 * The Call method.
	 * 
	 * @param parent
	 *            The parent component
	 * @param anQuestion
	 *            The question that's to be confirmed.
	 * @return String from the input textbox.
	 */
	public static String show(Component parent) {
		return new InputMessageTextBox(parent).getMsg();
	}

	/**
	 * private constructor. So it can only be created with the static show()
	 * method.
	 * 
	 * @param parent
	 * @param anQuestion
	 */
	private InputMessageTextBox(Component parent) {
		super();

		textbox = new Textbox();

		setParent(parent);

		try {
			userName = ((UserImpl) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUsername();
		} catch (Exception e) {
			e.printStackTrace();
		}

		createBox();
	}

	private void createBox() {

		setWidth("350px");
		setHeight("150px");
		setTitle(Labels.getLabel("message.Information.PleaseInsertText"));
		setId("confBox");
		setVisible(true);
		setClosable(true);
		addEventListener("onOK", new OnCloseListener());

		// Hbox hbox = new Hbox();
		// hbox.setWidth("100%");
		// hbox.setParent(this);
		// Checkbox cb = new Checkbox();
		// cb.setLabel(Labels.getLabel("common.All"));
		// cb.setChecked(true);

		Separator sp = new Separator();
		sp.setParent(this);

		textbox.setWidth("98%");
		textbox.setHeight("80px");
		textbox.setMultiline(true);
		textbox.setRows(5);
		textbox.setParent(this);

		Separator sp2 = new Separator();
		sp2.setBar(true);
		sp2.setParent(this);

		Button btnSend = new Button();
		btnSend.setLabel(Labels.getLabel("common.Send"));
		btnSend.setParent(this);
		btnSend.addEventListener("onClick", new EventListener() {

			@Override
			public void onEvent(Event event) throws Exception {

				// Check if empty, than do not send
				if (StringUtils.isEmpty(StringUtils.trim(textbox.getText()))) {
					onClose();
					return;
				}

				msg = msg + ZksampleDateFormat.getDateTimeLongFormater().format(new Date()) + " / " + Labels.getLabel("common.Message.From") + " " + userName + ":" + "\n";
				msg = msg + textbox.getText();
				msg = msg + "\n" + "_____________________________________________________" + "\n";

				onClose();
			}
		});

		try {
			doModal();
		} catch (SuspendNotAllowedException e) {
			logger.fatal("", e);
		} catch (InterruptedException e) {
			logger.fatal("", e);
		}
	}

	final class OnCloseListener implements EventListener {
		@Override
		public void onEvent(Event event) throws Exception {
			onClose();
		}
	}

	// +++++++++++++++++++++++++++++++++++++++++++++++++ //
	// ++++++++++++++++ Setter/Getter ++++++++++++++++++ //
	// +++++++++++++++++++++++++++++++++++++++++++++++++ //

	public void setMsg(String msg) {
		this.msg = msg;
	}

	public String getMsg() {
		return msg;
	}

}

It’s now at your hands to implement the logic for sending a message to a selected user or user groups in the InputMessageTextBox and the logic for listening only to the user’s account who is the receiver of the message in the MessageBarCtrl.

Samples are hostet in the Zksample2 project on

Have fun with it.

Stephan Gerth
Dipl.rer.pol.


PS: Help to prevent the global warming by writing cool software

How to create a StatusBarController with the zk framework ?

A simple statusBarController that works with the new zk5 EventQueues mechanism.

In this article we will create a statusBar that lay in the south area from a borderlayout and access it in a pretty simple way that the zk 5.x version will give us. Exactly the new EventQueues mechanism.

The statusBar should have 5 columns for UserName, OfficeId, selectedRecordObject (That we can see which i.e. customer is selected if we change the tab from listView to detailView).

One way is to create the columns of the statusBar in a zul-template like this:

pieces of the zul-template

            .  .  .
			<south id="south" border="none" margins="1,0,0,0"
				height="20px" splittable="false" flex="true">
				<div id="divSouth">

					<grid id="statusBarGrid" fixedLayout="true"
						height="20px" width="100%">
						<columns sizable="false">

							<column label="User:" width="10%"
								style="background-color: #D6DCDE;" />

							<column id="statusBarColUser" label=""
								width="10%" style="background-color: #D6DCDE;" />

							<column label="Office-No.:" width="10%"
								style="background-color: #D6DCDE;" />

							<column id="statusBarSelectedObject"
								width="30%" style="color: blue; background-color: #D6DCDE;" />

							<column id="statusBarAppVersion"
								style="color: #FF0000; background-color: #D6DCDE;" width="20%" />

							<column id="statusBarTableSchema"
								width="20%" style="color: blue; background-color: #D6DCDE;"
								align="left" />

						</columns>
					</grid>
				</div>

			</south>
		</borderlayout>

It should looks like in this picture:

StatusBarController

StatusBarController

As before zk 5.x we can do actualizing such statusBar columns in the old way by getting the needed objects with a chain of getFellow()’s or a little smaller with autowireing the components with a GenericForwardComposer.

pieces of the old java controller code

            .  .  .
		// show the selected Customers data in the statusBar column 'statusBarSelectedObject'
		if (aCustomer != null) {
			Column aColumn = (Column) event.getPage().getFirstRoot().getFellowIfAny("statusBarSelectedObject");

			if (aColumn != null) {
				aColumn.setLabel("--> " + aCustomer.getName1() + ", " + aCustomer.getName2() + "; " + aCustomer.getZip() + "-" + aCustomer.getCity());
			}
		}

With the EventQueues mechanism ships with zk 5.x it’s easy to do such things in a more elegant way. Jump over namespaces or different controllers away. It works like a global installed listener that if once declared you can reach them from any piece in your application. For that fine way we will spend a little more time for coding the controller. In it we create a grid and the 5 localized columns. In the afterCompose() method we setup the EventQueues ‘Listeners’ for the 5 columns. Like ‘the same procedure as every year, James?’ we create all inside a window container component so we need only one line of code in the zul-template for declaring our statusBarController.

The controller code looks like this:

StatusBarCtrl.java


package de.forsthaus.webui.util;

import java.io.Serializable;

import org.apache.log4j.Logger;
import org.zkoss.util.resource.Labels;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.event.EventQueues;
import org.zkoss.zk.ui.util.GenericForwardComposer;
import org.zkoss.zul.Column;
import org.zkoss.zul.Columns;
import org.zkoss.zul.Grid;
import org.zkoss.zul.Window;

/**
 * =======================================================================<br>
 * StatusBarController. <br>
 * =======================================================================<br>
 * Works with the EventQueues mechanism of zk. ALl needed components are created
 * in this class. In the zul-template declare only this controller with
 * 'apply' to a window component.<br>
 * 
 * Declaration in the zul-file:<br>
 * 
 * <pre>
 * < borderlayout >
 *   . . .
 *    < !-- STATUS BAR AREA -- >
 *    < south id="south" border="none" margins="1,0,0,0"
 * 		height="20px" splittable="false" flex="true" >
 * 	      < div id="divSouth" >
 * 
 *          < !-- The StatusBar. Comps are created in the Controller -- >
 *          < window id="winStatusBar" apply="${statusBarCtrl}"
 *                   border="none" width="100%" height="100%" />
 * 
 *        < /div >
 *    < /south >
 *  < /borderlayout >
 * </pre>
 * 
 * call in java to actualize a columns label:
 * 
 * <pre>
 * EventQueues.lookup(&quot;userNameEventQueue&quot;, EventQueues.DESKTOP, true).publish(new Event(&quot;onChangeSelectedObject&quot;, null, &quot;new Value&quot;));
 * </pre>
 * 
 * Spring bean declaration:
 * 
 * <pre>
 * < !-- StatusBarController -->
 * < bean id="statusBarCtrl" class="de.forsthaus.webui.util.StatusBarCtrl"
 *    scope="prototype">
 * < /bean>
 * </pre>
 * 
 * since: zk 5.0.0
 * 
 * @author sgerth
 * 
 */
public class StatusBarCtrl extends GenericForwardComposer implements Serializable {

	private static final long serialVersionUID = 1L;
	private transient final static Logger logger = Logger.getLogger(StatusBarCtrl.class);

	protected Window winStatusBar; // autowired

	// Used Columns
	private Column statusBarColUser;
	private Column statusBarOfficeId; 
	private Column statusBarSelectedObject;
	private Column statusBarAppVersion;
	private Column statusBarTableSchema;

	// Localized labels for the columns
	private String _labelUser = Labels.getLabel("common.User") + ": ";
	private String _labelOfficeId = Labels.getLabel("common.OfficeId") + ": ";
	private String _labelSelectedObject = Labels.getLabel("common.SelectedSign") + ": ";
	private String _labelAppVersion = Labels.getLabel("common.Version") + ": ";
	private String _labelTableSchema = Labels.getLabel("common.TableSchema") + ": ";

	/**
	 * Default constructor.
	 */
	public StatusBarCtrl() {
		super();

		if (logger.isDebugEnabled()) {
			logger.debug("--> super()");
		}
	}

	@Override
	public void doAfterCompose(Component window) throws Exception {
		super.doAfterCompose(window);

		// Listener for Username
		EventQueues.lookup("userNameEventQueue", EventQueues.DESKTOP, true).subscribe(new EventListener() {
			public void onEvent(Event event) throws Exception {
				String msg = (String) event.getData();
				statusBarColUser.setLabel(_labelUser + msg);
			}
		});

		// Listener for OfficeId
		EventQueues.lookup("officeIdEventQueue", EventQueues.DESKTOP, true).subscribe(new EventListener() {
			public void onEvent(Event event) throws Exception {
				String msg = (String) event.getData();
				statusBarOfficeId.setLabel(_labelOfficeId + msg);
			}
		});

		// Listener for selected Record
		EventQueues.lookup("selectedObjectEventQueue", EventQueues.DESKTOP, true).subscribe(new EventListener() {
			public void onEvent(Event event) throws Exception {
				String msg = (String) event.getData();
				statusBarSelectedObject.setLabel(_labelSelectedObject + msg);
			}
		});

		// Listener for applicationVersion
		EventQueues.lookup("appVersionEventQueue", EventQueues.DESKTOP, true).subscribe(new EventListener() {
			public void onEvent(Event event) throws Exception {
				String msg = (String) event.getData();
				statusBarAppVersion.setLabel(_labelAppVersion + msg);
			}
		});

		// Listener for TableSchemaName
		EventQueues.lookup("tableSchemaEventQueue", EventQueues.DESKTOP, true).subscribe(new EventListener() {
			public void onEvent(Event event) throws Exception {
				String msg = (String) event.getData();
				statusBarTableSchema.setLabel(_labelTableSchema + msg);
			}
		});

	}

	/**
	 * Automatically called method from zk.
	 * 
	 * @param event
	 */
	public void onCreate$winStatusBar(Event event) {

		Grid grid = new Grid();
		grid.setHeight("100%");
		grid.setWidth("100%");
		grid.setParent(winStatusBar);

		Columns columns = new Columns();
		columns.setSizable(false);
		columns.setParent(grid);

		statusBarColUser = new Column();
		statusBarColUser.setLabel(_labelUser);
		statusBarColUser.setWidth("10%");
		statusBarColUser.setStyle("background-color: #D6DCDE;");
		statusBarColUser.setParent(columns);

		statusBarOfficeId = new Column();
		statusBarOfficeId.setLabel(_labelOfficeId);
		statusBarOfficeId.setWidth("10%");
		statusBarOfficeId.setStyle("background-color: #D6DCDE;");
		statusBarOfficeId.setParent(columns);

		statusBarSelectedObject = new Column();
		statusBarSelectedObject.setLabel(_labelSelectedObject);
		statusBarSelectedObject.setWidth("30%");
		statusBarSelectedObject.setStyle("background-color: #D6DCDE; color: blue;");
		statusBarSelectedObject.setParent(columns);

		statusBarAppVersion = new Column();
		statusBarAppVersion.setLabel(_labelAppVersion);
		statusBarAppVersion.setWidth("20%");
		statusBarAppVersion.setStyle("background-color: #D6DCDE; color: #FF0000;");
		statusBarAppVersion.setParent(columns);

		statusBarTableSchema = new Column();
		statusBarTableSchema.setLabel(_labelTableSchema);
		statusBarTableSchema.setWidth("10%");
		statusBarTableSchema.setStyle("background-color: #D6DCDE; color: blue;");
		statusBarTableSchema.setParent(columns);

	}
}

We can now add the statusBar in our zul-template with a single line of code:

As we mentioned we would have it in the south area of our borderlayout we moved it to there. Now the pieces of the zul-file looks like this:

pieces of the zul-template

   .  .  .
		    <!-- STATUS BAR AREA -->
			<south id="south" border="none" margins="1,0,0,0"
				height="20px" splittable="false" flex="true">
				<div id="divSouth">

					<!-- The StatusBar. Comps are created in the Controller -->
					<window id="winStatusBar" apply="${statusBarCtrl}" border="none" width="100%" height="100%" />

				</div>
			</south>
		</borderlayout>
   .  .  .

At last we have a look on how we call such a ‘listener’ . Therefore we imagine we have a listbox with an onSelect() event. By selecting an listItem we call the corresponding method an get the selected Item. In our case we get it from the DataBinder so we must not casting it to the right object. The .publish() method will send the events data to the EventQueues listener and there’s the code running that we have defined in the onEvent() method. The final code looks like here:

calling the EventQueue


	public void onSelect$listBoxCustomer(Event event) {

		Customer aCustomer = getSelectedCustomer();

		if (aCustomer != null) {
	        	
         		// show the objects data in the statusBar
		        EventQueues.lookup("selectedObjectEventQueue", EventQueues.DESKTOP, true).publish(new Event("onChangeSelectedObject", null, aCustomer.getName1()));
		}
	}

Samples are hostet in the Zksample2 project on

Have fun with it.

Stephan Gerth

Dipl.rer.pol.


PS: Help to prevent the global warming by writing cool software

Modal search dialogs. Part 3: ExtendedSearchListBox skeleton.

An extended modal searchBox/selectionList with paging and data limiting features which returns an object.

As we see in part 1 and part 2 of the modal search dialogs story we build all search/selection components in a modal window component and by closing these window we can get back the selected object from the list.

Database Paging is necessary if the application should be fast. Over all we need a functionality with which we can limit the amount of possible list results by manipulating the value of a table field for the sql where clause. For our ExtendedSearchListBox we do this by adding a textbox component and a search button. The textbox receives signs that must be occur with the data of the table field. We search in our backend method with the ‘like’ keyword, so that every record comes back where in their field ‘Description’ i.e. the signs ‘ar‘ exists. We start the retrieving of the records by pressing the search button right next the textbox. If we want get all records that we must clear the textbox and press the search button again.

From the backend we get back a helper class called: ResultObject() . This class holds only two things. First a generic list that we must cast them back and second an int value that represents the totalSize of possible records (not the paged one’s size).

calling in code:

     Bean bean = ExtendedSearchListBox.show(parentComponent);

     if ( bean != null ) {
       // do something
       }

This is a very simple call. We get back the selected object from the list by selecting it and click the OK button or by double clicking on a listItem. Otherwise by closing without selecting we get back null.

  • The classfile:

    /**
     * Copyright 2010 the original author or authors.
     * 
     * This file is part of Zksample2. http://zksample2.sourceforge.net/
     *
     * Zksample2 is free software: you can redistribute it and/or modify
     * it under the terms of the GNU General Public License as published by
     * the Free Software Foundation, either version 3 of the License, or
     * (at your option) any later version.
     * 
     * Zksample2 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 General Public License for more details.
     *
     * You should have received a copy of the GNU General Public License
     * along with Zksample2.  If not, see <http://www.gnu.org/licenses/gpl.html>.
     */
    package de.forsthaus.webui.util.searchdialogs;
    
    import java.io.Serializable;
    import java.util.List;
    
    import org.apache.log4j.Logger;
    import org.zkoss.spring.SpringUtil;
    import org.zkoss.util.resource.Labels;
    import org.zkoss.zk.ui.Component;
    import org.zkoss.zk.ui.SuspendNotAllowedException;
    import org.zkoss.zk.ui.event.Event;
    import org.zkoss.zk.ui.event.EventListener;
    import org.zkoss.zk.ui.sys.ComponentsCtrl;
    import org.zkoss.zkex.zul.Borderlayout;
    import org.zkoss.zkex.zul.Center;
    import org.zkoss.zkex.zul.North;
    import org.zkoss.zkex.zul.South;
    import org.zkoss.zul.Button;
    import org.zkoss.zul.Div;
    import org.zkoss.zul.Hbox;
    import org.zkoss.zul.ListModelList;
    import org.zkoss.zul.Listbox;
    import org.zkoss.zul.Listcell;
    import org.zkoss.zul.Listhead;
    import org.zkoss.zul.Listheader;
    import org.zkoss.zul.Listitem;
    import org.zkoss.zul.ListitemRenderer;
    import org.zkoss.zul.Paging;
    import org.zkoss.zul.Separator;
    import org.zkoss.zul.Textbox;
    import org.zkoss.zul.Window;
    import org.zkoss.zul.event.PagingEvent;
    
    import de.forsthaus.backend.bean.ResultObject;
    import de.forsthaus.backend.model.Branche;
    import de.forsthaus.backend.service.BrancheService;
    
    /**
     * This class creates a modal window as a dialog in which the user <br>
     * can search and select a branch object. By onClosing this box <b>returns</b>
     * an object or null. <br>
     * The object can returned by selecting and clicking the OK button or by
     * DoubleClicking on an item from the list.<br>
     * Further the count of results can limited by manipulating the value of a table
     * field for the sql where clause.<br>
     * <br>
     * This is a basic skeleton which is extended for database paging and an
     * additionally textbox for inserting a searchparameter.<br>
     * <br>
     * 
     * <pre>
     * call: Branch branch = BranchExtendedSearchListBox.show(parentComponent);
     * </pre>
     * 
     * @author bbruhns
     * @author sgerth
     */
    public class BranchExtendedSearchListBox extends Window implements Serializable {
    
    	private static final long serialVersionUID = 1L;
    	private static final Logger logger = Logger.getLogger(BranchExtendedSearchListBox.class);
    
    	// the textbox for inserting the searchparameter
    	private Textbox _textbox;
    
    	// button for sending the ServiceMethod if searchParameters are used
    	private Button _searchButton;
    
    	// the paging component
    	private Paging _paging;
    
    	// pageSize
    	private int pageSize = 18;
    
    	// the data listbox
    	private Listbox listbox;
    
    	// the model for the listbox
    	private ListModelList listModelList;
    
    	// the windows title
    	private String _title = Labels.getLabel("message.Information.ExtendedSearch") + " / " + Labels.getLabel("common.Branch");
    
    	// 1. Listheader
    	private String _listHeader1 = Labels.getLabel("common.Description");
    
    	// the windows height
    	private int _height = 410;
    
    	// the windows width
    	private int _width = 300;
    
    	// the returned bean object
    	private Branche branche = null;
    
    	// The service from which we get the data
    	private BrancheService brancheService;
    
    	/**
    	 * The Call method.
    	 * 
    	 * @param parent
    	 *            The parent component
    	 * @return a BeanObject from the listBox or null.
    	 */
    	public static Branche show(Component parent) {
    		return new BranchExtendedSearchListBox(parent).getBranche();
    	}
    
    	/**
    	 * Private Constructor. So it can only be created with the static show()
    	 * method.<br>
    	 * 
    	 * @param parent
    	 */
    	private BranchExtendedSearchListBox(Component parent) {
    		super();
    
    		setParent(parent);
    
    		createBox();
    	}
    
    	/**
    	 * Creates the components, sets the model and show the window as modal.<br>
    	 */
    	@SuppressWarnings("unchecked")
    	private void createBox() {
    
    		// Window
    		this.setWidth(String.valueOf(_width) + "px");
    		this.setHeight(String.valueOf(_height) + "px");
    		this.setTitle(_title);
    		this.setVisible(true);
    		this.setClosable(true);
    
    		// Borderlayout
    		Borderlayout bl = new Borderlayout();
    		bl.setHeight("100%");
    		bl.setWidth("100%");
    		bl.setParent(this);
    
    		Center center = new Center();
    		center.setBorder("none");
    		center.setFlex(true);
    		center.setParent(bl);
    
    		// Borderlayout
    		Borderlayout bl2 = new Borderlayout();
    		bl2.setHeight("100%");
    		bl2.setWidth("100%");
    		bl2.setParent(center);
    
    		North north2 = new North();
    		north2.setBorder("none");
    		north2.setHeight("26px");
    		north2.setParent(bl2);
    		// Paging
    		_paging = new Paging();
    		_paging.setDetailed(true);
    		_paging.addEventListener("onPaging", new OnPagingEventListener());
    		_paging.setPageSize(getPageSize());
    		_paging.setParent(north2);
    
    		Center center2 = new Center();
    		center2.setBorder("none");
    		center2.setFlex(true);
    		center2.setParent(bl2);
    		// Div Center area
    		Div divCenter2 = new Div();
    		divCenter2.setWidth("100%");
    		divCenter2.setHeight("100%");
    		divCenter2.setParent(center2);
    
    		// Listbox
    		listbox = new Listbox();
    		// listbox.setStyle("border: none;");
    		listbox.setHeight("290px");
    		listbox.setVisible(true);
    		listbox.setParent(divCenter2);
    		listbox.setItemRenderer(new SearchBoxItemRenderer());
    	
    		Listhead listhead = new Listhead();
    		listhead.setParent(listbox);
    		Listheader listheader = new Listheader();
    		listheader.setParent(listhead);
    		listheader.setLabel(_listHeader1);
    
    		South south2 = new South();
    		south2.setBorder("none");
    		south2.setHeight("26px");
    		south2.setParent(bl2);
    		// hbox for holding the Textbox + SearchButton
    		Hbox hbox = new Hbox();
    		hbox.setPack("stretch");
    		hbox.setStyle("padding-left: 5px");
    		hbox.setWidth("100%");
    		hbox.setHeight("27px");
    		hbox.setParent(south2);
    		// textbox for inserting the search parameter
    		_textbox = new Textbox();
    		_textbox.setWidth("100%");
    		_textbox.setMaxlength(20);
    		_textbox.setParent(hbox);
    		// serachButton
    		_searchButton = new Button();
    		_searchButton.setImage("/images/icons/search.gif");
    		_searchButton.addEventListener("onClick", new OnSearchListener());
    		_searchButton.setParent(hbox);
    
    		South south = new South();
    		south.setBorder("none");
    		south.setHeight("30px");
    		south.setParent(bl);
    
    		Div divSouth = new Div();
    		divSouth.setWidth("100%");
    		divSouth.setHeight("100%");
    		divSouth.setParent(south);
    
    		Separator sep = new Separator();
    		sep.setBar(true);
    		sep.setOrient("horizontal");
    		sep.setParent(divSouth);
    
    		// Button
    		Button btnOK = new Button();
    		btnOK.setStyle("padding-left: 5px");
    		btnOK.setLabel("OK");
    		btnOK.addEventListener("onClick", new OnCloseListener());
    		btnOK.setParent(divSouth);
    
    		/**
    		 * init the model.<br>
    		 * The ResultObject is a helper class that holds the generic list and
    		 * the totalRecord count as int value.
    		 */
    		ResultObject ro = getBrancheService().getAllBranchesLikeText("", 0, getPageSize());
    		List<Branche> resultList = (List<Branche>) ro.getList();
    		_paging.setTotalSize(ro.getTotalCount());
    
    		// set the model
    		setListModelList(new ListModelList(resultList));
    		listbox.setModel(getListModelList());
    
    		try {
    			doModal();
    		} catch (SuspendNotAllowedException e) {
    			logger.fatal("", e);
    			this.detach();
    		} catch (InterruptedException e) {
    			logger.fatal("", e);
    			this.detach();
    		}
    	}
    
    	/**
    	 * Inner ListItemRenderer class.<br>
    	 */
    	final class SearchBoxItemRenderer implements ListitemRenderer {
    
    		@Override
    		public void render(Listitem item, Object data) throws Exception {
    
    			Branche branche = (Branche) data;
    
    			Listcell lc = new Listcell(branche.getBraBezeichnung());
    			lc.setParent(item);
    
    			item.setAttribute("data", data);
    			ComponentsCtrl.applyForward(item, "onDoubleClick=onDoubleClicked");
    		}
    	}
    
    	/**
    	 * If a DoubleClick appears on a listItem. <br>
    	 * This method is forwarded in the renderer.<br>
    	 * 
    	 * @param event
    	 */
    	public void onDoubleClicked(Event event) {
    
    		if (listbox.getSelectedItem() != null) {
    			Listitem li = listbox.getSelectedItem();
    			Branche branche = (Branche) li.getAttribute("data");
    
    			setBranche(branche);
    			this.onClose();
    		}
    	}
    
    	/**
    	 * "onPaging" EventListener for the paging component. <br>
    	 * <br>
    	 * Calculates the next page by currentPage and pageSize values. <br>
    	 * Calls the method for refreshing the data with the new rowStart and
    	 * pageSize. <br>
    	 */
    	public final class OnPagingEventListener implements EventListener {
    		@Override
    		public void onEvent(Event event) throws Exception {
    
    			PagingEvent pe = (PagingEvent) event;
    			int pageNo = pe.getActivePage();
    			int start = pageNo * getPageSize();
    
    			if (logger.isDebugEnabled()) {
    				logger.debug("--> : " + start + "/" + getPageSize());
    			}
    
    			String searchText = _textbox.getValue();
    			// refresh the list
    			refreshModel(searchText, start);
    		}
    	}
    
    	/**
    	 * Refreshes the list by calling the DAO methode with the modified search
    	 * object. <br>
    	 * 
    	 * @param so
    	 *            SearchObject, holds the entity and properties to search. <br>
    	 * @param start
    	 *            Row to start. <br>
    	 */
    	@SuppressWarnings("unchecked")
    	void refreshModel(String searchText, int start) {
    
    		// clear old data
    		getListModelList().clear();
    
    		// init the model
    		ResultObject ro = getBrancheService().getAllBranchesLikeText(searchText, start, getPageSize());
    		List<Branche> resultList = (List<Branche>) ro.getList();
    		_paging.setTotalSize(ro.getTotalCount());
    
    		// set the model
    		setListModelList(new ListModelList(resultList));
    		listbox.setModel(getListModelList());
    	}
    
    	/**
    	 * Inner OnSearchListener class.<br>
    	 */
    	final class OnSearchListener implements EventListener {
    		@Override
    		public void onEvent(Event event) throws Exception {
    
    			String searchText = _textbox.getValue();
    
    			// we start new
    			refreshModel(searchText, 0);
    		}
    	}
    
    	/**
    	 * Inner OnCloseListener class.<br>
    	 */
    	final class OnCloseListener implements EventListener {
    		@Override
    		public void onEvent(Event event) throws Exception {
    
    			if (listbox.getSelectedItem() != null) {
    				Listitem li = listbox.getSelectedItem();
    				Branche branche = (Branche) li.getAttribute("data");
    
    				setBranche(branche);
    			}
    			onClose();
    		}
    	}
    
    	// +++++++++++++++++++++++++++++++++++++++++++++++++ //
    	// ++++++++++++++++ Setter/Getter ++++++++++++++++++ //
    	// +++++++++++++++++++++++++++++++++++++++++++++++++ //
    
    	public Branche getBranche() {
    		return branche;
    	}
    
    	private void setBranche(Branche branche) {
    		this.branche = branche;
    	}
    
    	public BrancheService getBrancheService() {
    		if (brancheService == null) {
    			brancheService = (BrancheService) SpringUtil.getBean("brancheService");
    		}
    		return brancheService;
    	}
    
    	public void setBrancheService(BrancheService brancheService) {
    		this.brancheService = brancheService;
    	}
    
    	public void setPageSize(int pageSize) {
    		this.pageSize = pageSize;
    	}
    
    	public int getPageSize() {
    		return pageSize;
    	}
    
    	public void setListModelList(ListModelList listModelList) {
    		this.listModelList = listModelList;
    	}
    
    	public ListModelList getListModelList() {
    		return listModelList;
    	}
    
    }
    
    

    The helper classfile:

    /**
     * A helper class that can hold a generic list and an int value. Used as the
     * totalSize value of possible records for paging components.<br>
     * 
     * @author sgerth
     * 
     */
    public class ResultObject implements Serializable {
    
    	private static final long serialVersionUID = 1L;
    
    	// holds a generic List
    	private List<?> list;
    
    	// holds an int
    	private int totalCount;
    
    	public ResultObject() {
    	}
    
    	public ResultObject(List<?> list, int totalCount) {
    		super();
    		setList(list);
    		setTotalCount(totalCount);
    	}
    
    	public List<?> getList() {
    		return list;
    	}
    
    	public void setList(List<?> list) {
    		this.list = list;
    	}
    
    	public int getTotalCount() {
    		return totalCount;
    	}
    
    	public void setTotalCount(int totalCount) {
    		this.totalCount = totalCount;
    	}
    }
    
    

    The backend method uses Spring/Hibernate:

    	@SuppressWarnings("unchecked")
    	@Override
    	public ResultObject getAllBranchesLikeText(String text, int start, int pageSize) {
    		DetachedCriteria criteria = DetachedCriteria.forClass(Branche.class);
    
    		if (!StringUtils.isEmpty(text)) {
    			criteria.add(Restrictions.ilike("braBezeichnung", text, MatchMode.ANYWHERE));
    		}
    
    		criteria.addOrder(Order.asc("braBezeichnung"));
    
    		int totalCount = getHibernateTemplate().findByCriteria(criteria).size();
    
    		List<Branche> list = getHibernateTemplate().findByCriteria(criteria, start, pageSize);
    
    		return new ResultObject(list, totalCount);
    	}
    
    

    Samples are hostet in the Zksample2 project on

    Have fun with it.

    Stephan Gerth

    Dipl.rer.pol.


    PS: Help to prevent the global warming by writing cool software

    Modal search dialogs. Part 2: AdvancedSearchListBox skeleton.

    An advanced modal searchBox/selectionList with database paging which returns an object.

    part 1 SimpleSearchListBox
    part 3 ExtendedSearchListBox

    As we see in part 1 of the modal search dialogs story we build all search/selection components in a modal window component and by closing these window we can get back the selected object from the list.

    You’ll discover that these searchDialog is not really recommended for handling huge data amounts. In fact the underlying zk ListModelList will handle the data paging on the server and send back to the clients listbox only such count of records that are defined in the pageSize but holds all of the loaded records on the server. So the memory usage can increase rapidly.

    As a Webui framework the involved zk component cannot and need not know what backend technology we use. So we can catch the onPaging() event from the paging component to manipulate the outgoing database call for the needed records. In this case we get a real database paging where only the needed records for presenting in the listbox are loaded from the db.

    calling in code:

         Bean bean = AdvancedSearchListBox.show(parentComponent);
    
         if ( bean != null ) {
           // do something
           }
    

    The classfile:

    /**
     * Copyright 2010 the original author or authors.
     * 
     * This file is part of Zksample2. http://zksample2.sourceforge.net/
     *
     * Zksample2 is free software: you can redistribute it and/or modify
     * it under the terms of the GNU General Public License as published by
     * the Free Software Foundation, either version 3 of the License, or
     * (at your option) any later version.
     * 
     * Zksample2 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 General Public License for more details.
     *
     * You should have received a copy of the GNU General Public License
     * along with Zksample2.  If not, see <http://www.gnu.org/licenses/gpl.html>.
     */
    package de.forsthaus.webui.util.searchdialogs;
    
    import java.io.Serializable;
    import java.util.List;
    
    import org.apache.log4j.Logger;
    import org.zkoss.spring.SpringUtil;
    import org.zkoss.util.resource.Labels;
    import org.zkoss.zk.ui.Component;
    import org.zkoss.zk.ui.SuspendNotAllowedException;
    import org.zkoss.zk.ui.event.Event;
    import org.zkoss.zk.ui.event.EventListener;
    import org.zkoss.zk.ui.sys.ComponentsCtrl;
    import org.zkoss.zkex.zul.Borderlayout;
    import org.zkoss.zkex.zul.Center;
    import org.zkoss.zkex.zul.South;
    import org.zkoss.zul.Button;
    import org.zkoss.zul.Div;
    import org.zkoss.zul.ListModelList;
    import org.zkoss.zul.Listbox;
    import org.zkoss.zul.Listcell;
    import org.zkoss.zul.Listhead;
    import org.zkoss.zul.Listheader;
    import org.zkoss.zul.Listitem;
    import org.zkoss.zul.ListitemRenderer;
    import org.zkoss.zul.Paging;
    import org.zkoss.zul.Window;
    import org.zkoss.zul.event.PagingEvent;
    
    import de.forsthaus.backend.bean.ResultObject;
    import de.forsthaus.backend.model.Branche;
    import de.forsthaus.backend.service.BrancheService;
    
    /**
     * This class creates a modal window as a dialog in which the user <br>
     * can search and select a branch object. By onClosing this box <b>returns</b>
     * an object or null. <br>
     * The object can returned by selecting and clicking the OK button or by
     * DoubleClicking on an item from the list.<br>
     * 
     * <br>
     * This is a basic skeleton which is extended for database paging.<br>
     * <br>
     * 
     * <pre>
     * call: Branch branch = BranchAdvancedSearchListBox.show(parentComponent);
     * </pre>
     * 
     * @author bbruhns
     * @author sgerth
     */
    public class BranchAdvancedSearchListBox extends Window implements Serializable {
    
    	private static final long serialVersionUID = 1L;
    	private static final Logger logger = Logger.getLogger(BranchAdvancedSearchListBox.class);
    
    	// the paging component
    	private Paging _paging;
    
    	// pageSize
    	private int pageSize = 19;
    
    	// the data listbox
    	private Listbox listbox;
    
    	// the model for the listbox
    	private ListModelList listModelList;
    
    	// the windows title
    	private String _title = Labels.getLabel("message.Information.AdvancedSearch") + " / " + Labels.getLabel("common.Branch");
    
    	// 1. Listheader
    	private String _listHeader1 = Labels.getLabel("common.Description");
    
    	// the windows height
    	private int _height = 400;
    
    	// the windows width
    	private int _width = 300;
    
    	// the returned bean object
    	private Branche branche = null;
    
    	// The service from which we get the data
    	private BrancheService brancheService;
    
    	/**
    	 * The Call method.
    	 * 
    	 * @param parent
    	 *            The parent component
    	 * @return a BeanObject from the listBox or null.
    	 */
    	public static Branche show(Component parent) {
    		return new BranchAdvancedSearchListBox(parent).getBranche();
    	}
    
    	/**
    	 * Private Constructor. So it can only be created with the static show()
    	 * method.<br>
    	 * 
    	 * @param parent
    	 */
    	private BranchAdvancedSearchListBox(Component parent) {
    		super();
    
    		setParent(parent);
    
    		createBox();
    	}
    
    	/**
    	 * Creates the components, sets the model and show the window as modal.<br>
    	 */
    	@SuppressWarnings("unchecked")
    	private void createBox() {
    
    		// Window
    		this.setWidth(String.valueOf(_width) + "px");
    		this.setHeight(String.valueOf(_height) + "px");
    		this.setTitle(_title);
    		this.setVisible(true);
    		this.setClosable(true);
    
    		// Borderlayout
    		Borderlayout bl = new Borderlayout();
    		bl.setHeight("100%");
    		bl.setWidth("100%");
    		bl.setParent(this);
    
    		Center center = new Center();
    		center.setFlex(true);
    		center.setParent(bl);
    
    		South south = new South();
    		south.setHeight("26px");
    		south.setParent(bl);
    
    		// Button
    		Button btnOK = new Button();
    		btnOK.setLabel("OK");
    		btnOK.addEventListener("onClick", new OnCloseListener());
    		btnOK.setParent(south);
    
    		Div divCenter = new Div();
    		divCenter.setWidth("100%");
    		divCenter.setHeight("100%");
    		divCenter.setParent(center);
    
    		// Paging
    		_paging = new Paging();
    		_paging.addEventListener("onPaging", new OnPagingEventListener());
    		_paging.setPageSize(getPageSize());
    		_paging.setParent(divCenter);
    
    		// Listbox
    		listbox = new Listbox();
    		listbox.setStyle("border: none;");
    		listbox.setHeight("100%");
    		listbox.setVisible(true);
    		listbox.setParent(divCenter);
    		listbox.setItemRenderer(new SearchBoxItemRenderer());
    
    		Listhead listhead = new Listhead();
    		listhead.setParent(listbox);
    		Listheader listheader = new Listheader();
    		listheader.setParent(listhead);
    		listheader.setLabel(_listHeader1);
    
    		/**
    		 * init the model.<br>
    		 * The ResultObject is a helper class that holds the generic list and
    		 * the totalRecord count as int value.
    		 */
    		ResultObject ro = getBrancheService().getAllBranches(0, getPageSize());
    		List<Branche> resultList = (List<Branche>) ro.getList();
    		_paging.setTotalSize(ro.getTotalCount());
    
    		// set the model
    		setListModelList(new ListModelList(resultList));
    		listbox.setModel(getListModelList());
    
    		try {
    			doModal();
    		} catch (SuspendNotAllowedException e) {
    			logger.fatal("", e);
    			this.detach();
    		} catch (InterruptedException e) {
    			logger.fatal("", e);
    			this.detach();
    		}
    	}
    
    	/**
    	 * Inner ListItemRenderer class.<br>
    	 */
    	final class SearchBoxItemRenderer implements ListitemRenderer {
    
    		@Override
    		public void render(Listitem item, Object data) throws Exception {
    
    			Branche branche = (Branche) data;
    
    			Listcell lc = new Listcell(branche.getBraBezeichnung());
    			lc.setParent(item);
    
    			item.setAttribute("data", data);
    			ComponentsCtrl.applyForward(item, "onDoubleClick=onDoubleClicked");
    		}
    	}
    
    	/**
    	 * If a DoubleClick appears on a listItem. <br>
    	 * This method is forwarded in the renderer.<br>
    	 * 
    	 * @param event
    	 */
    	public void onDoubleClicked(Event event) {
    
    		if (listbox.getSelectedItem() != null) {
    			Listitem li = listbox.getSelectedItem();
    			Branche branche = (Branche) li.getAttribute("data");
    
    			setBranche(branche);
    			this.onClose();
    		}
    	}
    
    	/**
    	 * "onPaging" EventListener for the paging component. <br>
    	 * <br>
    	 * Calculates the next page by currentPage and pageSize values. <br>
    	 * Calls the method for refreshing the data with the new rowStart and
    	 * pageSize. <br>
    	 */
    	public final class OnPagingEventListener implements EventListener {
    		@Override
    		public void onEvent(Event event) throws Exception {
    
    			PagingEvent pe = (PagingEvent) event;
    			int pageNo = pe.getActivePage();
    			int start = pageNo * getPageSize();
    
    			if (logger.isDebugEnabled()) {
    				logger.debug("--> : " + start + "/" + getPageSize());
    			}
    
    			// refresh the list
    			refreshModel(start);
    		}
    	}
    
    	/**
    	 * Refreshes the list by calling the DAO methode with the modified search
    	 * object. <br>
    	 * 
    	 * @param so
    	 *            SearchObject, holds the entity and properties to search. <br>
    	 * @param start
    	 *            Row to start. <br>
    	 */
    	@SuppressWarnings("unchecked")
    	void refreshModel(int start) {
    
    		// clear old data
    		getListModelList().clear();
    
    		// init the model
    		ResultObject ro = getBrancheService().getAllBranches(start, getPageSize());
    		List<Branche> resultList = (List<Branche>) ro.getList();
    		_paging.setTotalSize(ro.getTotalCount());
    
    		// set the model
    		setListModelList(new ListModelList(resultList));
    		listbox.setModel(getListModelList());
    	}
    
    	/**
    	 * Inner OnCloseListener class.<br>
    	 */
    	final class OnCloseListener implements EventListener {
    		@Override
    		public void onEvent(Event event) throws Exception {
    
    			if (listbox.getSelectedItem() != null) {
    				Listitem li = listbox.getSelectedItem();
    				Branche branche = (Branche) li.getAttribute("data");
    
    				setBranche(branche);
    			}
    			onClose();
    		}
    	}
    
    	// +++++++++++++++++++++++++++++++++++++++++++++++++ //
    	// ++++++++++++++++ Setter/Getter ++++++++++++++++++ //
    	// +++++++++++++++++++++++++++++++++++++++++++++++++ //
    
    	public Branche getBranche() {
    		return branche;
    	}
    
    	private void setBranche(Branche branche) {
    		this.branche = branche;
    	}
    
    	public BrancheService getBrancheService() {
    		if (brancheService == null) {
    			brancheService = (BrancheService) SpringUtil.getBean("brancheService");
    		}
    		return brancheService;
    	}
    
    	public void setBrancheService(BrancheService brancheService) {
    		this.brancheService = brancheService;
    	}
    
    	public void setPageSize(int pageSize) {
    		this.pageSize = pageSize;
    	}
    
    	public int getPageSize() {
    		return pageSize;
    	}
    
    	public void setListModelList(ListModelList listModelList) {
    		this.listModelList = listModelList;
    	}
    
    	public ListModelList getListModelList() {
    		return listModelList;
    	}
    
    }
    
    
    

    For the backend helper class ResultObject() and the backend method please read part 3 of this article.

    Samples are hostet in the Zksample2 project on

    Have fun with it.

    Stephan Gerth

    Dipl.rer.pol.


    PS: Help to prevent the global warming by writing cool software

    Modal search dialogs. Part 1: SimpleSearchListBox skeleton.

    A modal searchBox/selectionList which returns an object.

    part 2 AdvancedSearchListBox
    part 3 ExtendedSearchListBox

    Imagine you have a form with several data fields and one or more of it will get their data by selecting it from a list. Such a list is often called as a DropDownList. With the zk framework you can solve this by using a listbox with mold=”select” and rows=”1″. The outstanding feature of such a component is that the ‘starter’ is in most cases a little button direct at the end of the input field and eveybody knows that he must click on this button to drop down the list. If you need some more options for limiting the count of records when the list appears you need an other way to solve this issue.

    One possibility is to take a so called bandbox component and place all needed data limiting functionality with the listbox on it.


    The second way we will shown in this article is to build a searchBox class with a modal window. For having the same behaviour we place a little starter button right next the input field that we whish to fill with a selected item from our SearchListBox. The advantage of our solution is that we can easily extended the SearchListBox for needed limitation components and logic features and get back an object of the needed bean from a window in a modal state.

    For this requirement we let our SimpleSearchListBox class created by a private constructor that we called in a static way.

  • calling in code:

         Bean bean = SimpleSearchListBox.show(parentComponent);
    
         if ( bean != null ) {
           // do something
           }
    

    The classfile:

    /**
    * Copyright 2010 the original author or authors.
    *
    * This file is part of Zksample2. http://zksample2.sourceforge.net/
    *
    * Zksample2 is free software: you can redistribute it and/or modify
    * it under the terms of the GNU General Public License as published by
    * the Free Software Foundation, either version 3 of the License, or
    * (at your option) any later version.
    *
    * Zksample2 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 General Public License for more details.
    *
    * You should have received a copy of the GNU General Public License
    * along with Zksample2.  If not, see .
    */
    package de.forsthaus.webui.util.searchdialogs;
    
    import org.apache.log4j.Logger;
    import org.zkoss.spring.SpringUtil;
    import org.zkoss.util.resource.Labels;
    import org.zkoss.zk.ui.Component;
    import org.zkoss.zk.ui.SuspendNotAllowedException;
    import org.zkoss.zk.ui.event.Event;
    import org.zkoss.zk.ui.event.EventListener;
    import org.zkoss.zk.ui.sys.ComponentsCtrl;
    import org.zkoss.zkex.zul.Borderlayout;
    import org.zkoss.zkex.zul.Center;
    import org.zkoss.zkex.zul.South;
    import org.zkoss.zul.Button;
    import org.zkoss.zul.ListModelList;
    import org.zkoss.zul.Listbox;
    import org.zkoss.zul.Listcell;
    import org.zkoss.zul.Listhead;
    import org.zkoss.zul.Listheader;
    import org.zkoss.zul.Listitem;
    import org.zkoss.zul.ListitemRenderer;
    import org.zkoss.zul.Window;
    
    import de.forsthaus.backend.model.Branche;
    import de.forsthaus.backend.service.BrancheService;
    
    /**
    * This class creates a modal window as a dialog in which the user
    * can search and select a branch object. By onClosing this box <strong>returns</strong>
    * an object or null.
    * The object can returned by selecting and clicking the OK button or by
    * DoubleClicking on an item from the list.
    *
    * This is a basic skeleton which can be extended for paging or additionally
    * textboxes for inserting searchparameters.
    *
    *
    * call: Branch branch = BranchSimpleSearchBox.show(parentComponent);
    *
    * @author bbruhns
    * @author sgerth
    */
    public class BranchSimpleSearchListBox extends Window {
    
    private static final long serialVersionUID = 8109634704496621100L;
    private static final Logger logger = Logger.getLogger(BranchSimpleSearchListBox.class);
    
    private Listbox listbox;
    // the windows title
    private String _title = Labels.getLabel("message.Information.Search") + " " + Labels.getLabel("common.Branch");
    // 1. Listheader
    private String _listHeader1 = Labels.getLabel("common.Description");
    // the windows height
    private int _height = 400;
    // the windows width
    private int _width = 300;
    
    // the returned bean object
    private Branche branche = null;
    
    // The service from which we get the data
    private BrancheService brancheService;
    
    /**
    * The Call method.
    *
    * @param parent
    *            The parent component
    * @return a BeanObject from the listBox or null.
    */
    public static Branche show(Component parent) {
    return new BranchSimpleSearchListBox(parent).getBranche();
    }
    
    /**
    * Private Constructor. So it can only be created with the static show() method.
    *
    * @param parent
    */
    private BranchSimpleSearchListBox(Component parent) {
    super();
    
    setParent(parent);
    
    createBox();
    }
    
    /**
    * Creates the components, sets the model and show the window as modal.
    */
    private void createBox() {
    
    // Window
    this.setWidth(String.valueOf(_width) + "px");
    this.setHeight(String.valueOf(_height) + "px");
    this.setTitle(_title);
    this.setVisible(true);
    this.setClosable(true);
    
    // Borderlayout
    Borderlayout bl = new Borderlayout();
    bl.setHeight("100%");
    bl.setWidth("100%");
    bl.setParent(this);
    
    Center center = new Center();
    center.setFlex(true);
    center.setParent(bl);
    
    South south = new South();
    south.setHeight("26px");
    south.setParent(bl);
    
    // Button
    Button btnOK = new Button();
    btnOK.setLabel("OK");
    btnOK.addEventListener("onClick", new OnCloseListener());
    btnOK.setParent(south);
    
    // Listbox
    listbox = new Listbox();
    listbox.setStyle("border: none;");
    listbox.setHeight("100%");
    listbox.setVisible(true);
    listbox.setParent(center);
    listbox.setItemRenderer(new SearchBoxItemRenderer());
    
    Listhead listhead = new Listhead();
    listhead.setParent(listbox);
    Listheader listheader = new Listheader();
    listheader.setParent(listhead);
    listheader.setLabel(_listHeader1);
    
    // Model
    listbox.setModel(new ListModelList(getBrancheService().getAlleBranche()));
    
    try {
    doModal();
    } catch (SuspendNotAllowedException e) {
    logger.fatal("", e);
    this.detach();
    } catch (InterruptedException e) {
    logger.fatal("", e);
    this.detach();
    }
    }
    
    /**
    * Inner ListItemRenderer class.
    */
    final class SearchBoxItemRenderer implements ListitemRenderer {
    
    @Override
    public void render(Listitem item, Object data) throws Exception {
    
    Branche branche = (Branche) data;
    
    Listcell lc = new Listcell(branche.getBraBezeichnung());
    lc.setParent(item);
    
    item.setAttribute("data", data);
    ComponentsCtrl.applyForward(item, "onDoubleClick=onDoubleClicked");
    }
    }
    
    /**
    * If a DoubleClick appears on a listItem.
    * This method is forwarded in the renderer.
    *
    * @param event
    */
    public void onDoubleClicked(Event event) {
    
    if (listbox.getSelectedItem() != null) {
    Listitem li = listbox.getSelectedItem();
    Branche branche = (Branche) li.getAttribute("data");
    
    setBranche(branche);
    this.onClose();
    }
    }
    
    /**
    * Inner OnCloseListener class.
    */
    final class OnCloseListener implements EventListener {
    
    @Override
    public void onEvent(Event event) throws Exception {
    
    if (listbox.getSelectedItem() != null) {
    Listitem li = listbox.getSelectedItem();
    Branche branche = (Branche) li.getAttribute("data");
    
    setBranche(branche);
    }
    onClose();
    }
    }
    
    // +++++++++++++++++++++++++++++++++++++++++++++++++ //
    // ++++++++++++++++ Setter/Getter ++++++++++++++++++ //
    // +++++++++++++++++++++++++++++++++++++++++++++++++ //
    
    public Branche getBranche() {
    return branche;
    }
    
    private void setBranche(Branche branche) {
    this.branche = branche;
    }
    
    public BrancheService getBrancheService() {
    if (brancheService == null) {
    brancheService = (BrancheService) SpringUtil.getBean("brancheService");
    }
    return brancheService;
    }
    
    public void setBrancheService(BrancheService brancheService) {
    this.brancheService = brancheService;
    }
    
    

    Samples are hostet in the Zksample2 project on

    Have fun with it.

    Stephan Gerth

    Dipl.rer.pol.


    PS: Help to prevent the global warming by writing cool software

    New ZK sample application sources available

    Yesterday we have checked in our new Zksample2 application as maven2 projects on sourceforge.net.
    It’s shows how you can build a robust and scalable enterprise web application by integrating commonly used frameworks like Hibernate, Spring, Spring-AOP, Spring-Security, JasperReports with the ZK Java web framework.
    You can reach the project homepage under the link here .

    You will find there 3 eclipse maven subprojects and the folder for the documentation.

    1. KeyGenZkoss = one-time-password generator
    2. spring-hibernate-backend = backend
    3. zkoss = frontend
    4. zksample2_doc = documentation

    The Documentation you can download seperately as a pdf-file from here .

    The documentation is a work in progress so be sure to check sometimes for the newest file.

    For checkout and evaluate or work with the application please download and read first the documentation.

    Mainly changes to the first sample app are:
    – change project structure as maven2 projects
    – spring managed frontend
    – securing methods with annotations @Secured() with our own implementation
    – login statistic
    – several integration options of ipToCountry
    – one-time-password sources are opened
    – Refactoring all Domain/DAO/Service Classes to english names
    – many many code changes
    – Revised PagedListWrapper
    – documentation

    We whish all fun with it and hope that it can be usefull for others.


    Authors: Stephan Gerth & Björn Bruhns

    Samples are hostet in the Zksample2 project on


    PS: Help to prevent the global warming by writing cool software

    Direct RIA: Die Zukunft von RIA

    Artikel: Direct RIA: Future of RIA / Author:  Robbie Cheng /  ZK Framework.

    Erschienen auf CodeGuru.com http://www.codeguru.com/java/article.php/c16445__1/

    Direkt RIA = Ansatz von Client + Server Verschmelzung

    Mehr Auswahl, schwierigere Entscheidung

    Obwohl Unternehmen von Rich-Internet-Anwendungen profitieren können, so kann die Einführung neuer Technologien auch Risiken beherbergen. Das erste Problem ist, das richtige Werkzeug für die gewünschte Lösung zu wählen. Hier kann es leicht zu einer falschen Entscheidung kommen aufgrund zu großer Auswahl, unklarer Kriterien, und komplexen Anforderungen.

    Produktivität oder Kontrollierbarkeit

    RIA (Rich Internet Application) Lösungen können in der Regel in zwei Kategorien eingestuft werden. Client- oder Server-seitig arbeitend.

    Client-seitige Frameworks sind wie manuelle Schaltgetriebe im  Auto, sie bieten mehr Kontrolle, erfordern aber auch mehr Aufwand. Im Gegensatz dazu verhalten sich Server-seitige Frameworks wie Automatik- Getriebe, die einfacher zu handhaben sind. Entwickler können durch AJAX-Technologie die Produktivität erhöhen und  transparenter gestalten.

    Die zu treffende Auswahl zwischen beiden Lösungsansätzen verursacht weiterhin Kopfschmerzen. Komplette Kontrolle oder Produktivität? Können wir von beiden Ansätzen zur gleichen Zeit profitieren? Der beste Fall wäre, dass unterschiedliche Anforderungen wie ein manuell schaltbares Automatik-Getriebe behandelt werden können.

    Direct RIA ermöglicht einen revolutionäre Ansatz von Client + Server Verschmelzung, der die Vorteile von Produktivität und Kontrollierbarkeit bei der Programmierung zur gleichen Zeit nutzt, je nach dem ob vollständige Anpassung oder Reaktionsfähigkeit benötigt wird.

    Übersicht über die Architektur von Direct RIA

    Direct RIA ist eine Server-seitige Lösung plus optionale Client-seitige Programmierung. Wenn Sie einen Blick auf die folgende Grafik nehmen, können Sie sehen, dass das Server-seitige Programmiermodell  dem Entwickler erlaubt die Web-Anwendung unter Verwendung von reinem Server-seitigen Code zu bauen.

    Der Server-seitige Code Generator erzeugt den benötigten HTML- und JavaScript-Code automatisch. Danach  wird der Client-seitige Code Generator mit dem DOM-Baum interagieren, um den Inhalt zu aktualisieren. Darüber hinaus ist die Synchronisation zwischen dem Browser und dem Server durch das  Zusammenspiel  des Client-seitigen und Server-seitigen AJAX Generators automatisiert. Entwickler können sich so auf das Erstellen der Anwendung konzentrieren als auf die komplexen AJAX-Technologien.

    Allerdings ist einer der größten Nachteile des reinen Server-seitigen Programmiermodells, dass die Entwickler nicht vollständig die Darstellung der Benutzeroberfläche kontrollieren können. Um dieses Problem zu überwinden, ermöglicht Direct RIA ein zusätzliches Client-seitiges Programmiermodell, das es Entwicklern ermöglicht Client-Code zu schreiben um, wenn nötig, die Benutzeroberfläche direkt zu kontrollieren.

    Direkter Oberflächen Zugriff

    Da die Anwendung auf dem Server läuft  kann sie auf Widgets direkt zugreifen. Nehmen wir das ZK Framework als ein Beispiel und erstellen ein Java-2D-Objekt auf dem Server, und geben dieses Objekt einfach in das Widget. Die Nutzer werden das Bild auf dem Browser  sehen, sobald sie auf die Schaltfläche klicken.


    <image id="image">
    <button onClick='draw(10,10,10,10)'/>
    <zscript>
    void draw( int x1, int y1, int x2, int y2) {
    LiveImage li = new LiveImage(400, 300, LiveImage.TYPE_INT_RGB);
    Graphics2D g2d = li.createGraphics();
    Line2D line = new Line2D.Double(x1, y1, x2, y2); g2d.draw(line);
    image.setContent(Images.encode("test.png", li));
    }
    </zscript>
    

    Mit Direct RIA, müssen sich Entwicklern nicht mehr um Client-seitige Programmierung kümmern. Sie können also sehr schnell ein Projekt beginnen ohne die vielen Client-seitigen Technologien zu erlernen.

    - Keine Client-seitige Programmierung.


    Direkter Datenzugriff

    Darüber hinaus kann die Applikation leicht und direkt auf Server-Ressourcen zugreifen, einschließlich Datenbank- und Web-Services, da beide sowohl das Frontend als auch das Backend auf der Server-Seite laufen. Das folgende Beispiel zeigt ein einfaches Szenario, um Daten aus der Datenbank zu lesen, und zeigt sie dem Anwender mithilfe des ZK Frameworks. Sobald der Benutzer auf die Schaltfläche klickt, erscheint eine Willkommens Nachricht.

    
    Hi. <label id="name"/>
    
    <button>
    
    <attribute name="onClick">
    
    User usr = Database.getUserById(1);
    
    name.setValue(usr.getName());
    
    </attribute>
    
    </button>
    
    

    Eine der schwierigsten Herausforderungen bei der Erstellung von Web-Anwendungen liegt in im asynchronen Programmiermodell, welches die verschiedenen Schritte enthält, um Daten vom Server zu bekommen und entsprechend den DOM-Baum zu aktualisieren. Mit Direct RIA jedoch können Frontend und Backend nahtlos integriert werden.

    - Keine asynchrone Kommunikation mehr.


    Direkte Live Daten

    Mit Live-Daten können Entwickler die Daten von der View trennen. Entwickler können die Daten durch die Implementierung des ListModel Interfaces anbieten. Das ZK Framework ermöglicht diesen Weg anstatt der direkte Manipulation der Daten.

    
    <zscript>
    
    String[] data = new  String[1000]; for ( int  j=0; j < data.length; ++j) {
    
    data[j] = "option "+j;
    
    }
    
    ListModel strset = new  SimpleListModel(data);
    
    </zscript>
    
    <grid width="100px" height="100px" model="${strset}">
    
    <columns>
    
    <column label="options"/>
    
    </columns>
    
    </grid>
    
    

    Das Grid sendet die Daten nur dann an den Client, wenn es sichtbar ist. Es spart so eine Menge des Netzwerkverkehrs, wenn die Datenmenge sehr groß ist.

    -Kein Problem mehr mit der Skalierbarkeit.


    Direkte Klienten Kontrolle

    Mit Direct Client Control kann der Entwickler Widgets entweder in Java-Script oder einer Markup-Sprache entwickeln und die Funktionen im Klienten implementieren um so das Verhalten der Antwortzeiten zu verbessern. Im folgenden Beispiel zeigen wir eine einfache Funktion zur Anzeige einer User-Eingabe mittels reiner Client-Programmierung. Diese wird  mit der Markup-Sprache von ZK umgesetzt.

    <page id="main">
    <textbox id="searchBox"/>
    <label id="value">
    </page>
    <script>
    zk.zuml.Parser.createAt( '#main', null, null, function (page) {
    page.$f('searchBox').listen({onChanging: function (event) {
    page.$f( 'value').setValue(event.data.value);}});
    </script>
    

    Entwicklern steht es frei, eine Funktion auf dem Client-Seite anpassen, um ihre unterschiedlichen Anforderungen gerecht zu werden.

    - Keine Anpassung Probleme mehr.


    Direct RIA ist die Zukunft der RIA

    Es ist nie eine leichte Aufgabe eine Enterprise-Anwendung zu erstellen, ganz zu schweigen die Benutzer-Schnittstelle zur selben Zeit zu erzeugen. Darüber hinaus ist es nicht leicht, die richtige Lösung zu wählen bei über 200 Lösungen für die verschiedensten Anforderungen. Direct RIA bietet den Ansatz für eine Client-Server Verschmelzung so dass Entwickler ihre Produktivität steigern können. Mit Hilfe des Direct RIA Programmiermodells kann sowohl auf Frontend und Backend direkt zugreifen werden, außerdem steht es Entwicklern frei, wenn nötig Funktion auf der Client-Seite zu erstellen. Direct RIA weist darauf hin, eine Komplettlösung für Entwickler zu sein, die die  Vorteile der gleichzeitigen Nutzung  von Produktivität und Kontrollierbarkeit zur Verfügung stellt.

    Über den Autor

    Robbie Cheng ist ein Evangelist des ZK Frameworks. Er ist der Hauptentwickler von ZK Mobile für Android und ZK Forum. Er ist der Co-Autor des Buches “ZK: Ajax ohne Javascript Framework” und hat zahlreiche Artikel im AJAXWorld Mgazine, TheServerSide und Javalobby veröffentlicht. Weiterhin ist Robbie auch bei verschiedenen Veranstaltungen wie, Google Developer Day, Mobile Monday, und OSDC 2009 als Redner aufgetreten.

    Übersetzt aus dem englischen von Stephan Gerth.

    New All-In ZKoss Sample Application

    Today i have checked in a ZKoss sample application in the google subversion repository that uses following frameworks:

  • Spring
  • Spring-Security (i have extended the rights management upon a group/group-rights and loaded all from a table, for allow customizing without a new tomcat start while i’m not using therefore the configuration file.)
  • Hibernate as an ORM.
  • JasperReports for reporting.
  • Generic-Hibernate-DAO for creating hql queries from a search-object. Used for all listboxes.
  • H2 DB v1.1.15 for a easier demo mode, which is started and filled with demo-data by deploying the application on tomcat.
    • You can checked out both as Eclipse 3.4 projects here:

      The Frontend
      The Backend

      Samples are hostet in the Zksample2 project on

      Have fun with it.

      Stephan Gerth

      Dipl.rer.pol.


      PS: Help to prevent the global warming by writing cool software