<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>ZKoss Java and the world</title>
	<atom:link href="http://www.forsthaus.de/blog/?feed=rss2" rel="self" type="application/rss+xml" />
	<link>http://www.forsthaus.de/blog</link>
	<description>a blog about the zk framework</description>
	<lastBuildDate>Wed, 01 Sep 2010 14:40:09 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>How to create a MessageSystem with the zk framework ?</title>
		<link>http://www.forsthaus.de/blog/?p=579</link>
		<comments>http://www.forsthaus.de/blog/?p=579#comments</comments>
		<pubDate>Tue, 31 Aug 2010 17:03:23 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[- ZK framework]]></category>

		<guid isPermaLink="false">http://www.forsthaus.de/blog/?p=579</guid>
		<description><![CDATA[




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 [...]]]></description>
			<content:encoded><![CDATA[<!-- Easy AdSense V2.59 -->
<!-- Post[count: 3] -->
<div class="ezAdsense adsense adsense-leadin" style="float:right;margin:12px;" ><script type="text/javascript"><!--
google_ad_client = "pub-5646410334266722";
/* 234x60, Erstellt 11.07.09 */
google_ad_slot = "9404605573";
google_ad_width = 234;
google_ad_height = 60;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></div><p><strong>A simple messageBarController that works with the new zk5 <strong>EventQueues</strong> mechanism. </strong></p>
<p>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 <a href="http://www.forsthaus.de/blog/?p=515">post</a>.</p>
<p>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. The right next icon is for opening a little window for writing a message text who can be send to all users.</p>
<div class="wp-caption alignnone" style="width: 547px"><img title="messageBar1" src="http://www.forsthaus.de/zkoss/pics/messageBar1.jpg" alt="Message Bar component" width="537" height="99" /><p class="wp-caption-text">Message Bar component</p></div>
<p><span style="text-decoration: underline;"> pieces of the zul-template </span></p>
<p><code>
<pre class="brush: xml;">
.  .  .
		&lt;!-- STATUS BAR AREA --&gt;
			&lt;south id=&quot;south&quot; border=&quot;none&quot; height=&quot;22px&quot;
				splittable=&quot;false&quot;&gt;

				&lt;div id=&quot;divSouth&quot; align=&quot;left&quot;
					style=&quot;float: left; padding: 0px&quot; width=&quot;100%&quot;&gt;

					&lt;borderlayout width=&quot;100%&quot; height=&quot;22px&quot;&gt;

						&lt;west border=&quot;none&quot; width=&quot;50px&quot;&gt;
							&lt;!-- The MessageBar. Comps are created in the Controller --&gt;
							&lt;window id=&quot;winMessageBar&quot;
								apply=&quot;${messageBarCtrl}&quot; border=&quot;none&quot; width=&quot;50px&quot;
								height=&quot;22px&quot; /&gt;
						&lt;/west&gt;

						&lt;center border=&quot;none&quot;&gt;
							&lt;!-- The StatusBar. Comps are created in the Controller --&gt;
							&lt;window id=&quot;winStatusBar&quot;
								apply=&quot;${statusBarCtrl}&quot; border=&quot;none&quot; width=&quot;100%&quot;
								height=&quot;22px&quot; /&gt;
						&lt;/center&gt;

					&lt;/borderlayout&gt;

				&lt;/div&gt;

			&lt;/south&gt;
.  .  .
</pre>
<p></code></p>
<p>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.</p>
<p><span style="text-decoration: underline;"> MessageBarCtrl.java </span></p>
<p><code>
<pre class="brush: java;">
/**
 * =======================================================================&lt;br&gt;
 * MessageBarController. &lt;br&gt;
 * =======================================================================&lt;br&gt;
 * 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.&lt;br&gt;
 * This MessageBarController is for sending and receiving messages from other
 * users.&lt;br&gt;
 *
 * The message text we do input with a special helper window that is called
 * InputMessageTextBox.java
 *
 * &lt;pre&gt;
 * &lt; borderlayout &gt;
 *   . . .
 *    &lt; !-- STATUS BAR AREA -- &gt;
 *    &lt; south id=&quot;south&quot; border=&quot;none&quot; margins=&quot;1,0,0,0&quot;
 * 		height=&quot;20px&quot; splittable=&quot;false&quot; flex=&quot;true&quot; &gt;
 * 	      &lt; div id=&quot;divSouth&quot; &gt;
 *
 *          &lt; !-- The MessageBar. Comps are created in the Controller -- &gt;
 *          &lt; window id=&quot;winMessageBar&quot; apply=&quot;${messageBarCtrl}&quot;
 *                   border=&quot;none&quot; width=&quot;100%&quot; height=&quot;100%&quot; /&gt;
 *          &lt; !-- The StatusBar. Comps are created in the Controller -- &gt;
 *          &lt; window id=&quot;winStatusBar&quot; apply=&quot;${statusBarCtrl}&quot;
 *                   border=&quot;none&quot; width=&quot;100%&quot; height=&quot;100%&quot; /&gt;
 *        &lt; /div &gt;
 *    &lt; /south &gt;
 *  &lt; /borderlayout &gt;
 * &lt;/pre&gt;
 *
 * call for the message system:
 *
 * &lt;pre&gt;
 * EventQueues.lookup(&amp;quot;userNameEventQueue&amp;quot;, EventQueues.APPLICATION, true).publish(new Event(&amp;quot;onChangeSelectedObject&amp;quot;, null, &amp;quot;new Value&amp;quot;));
 * &lt;/pre&gt;
 *
 *
 * Spring bean declaration:
 *
 * &lt;pre&gt;
 * &lt; !-- MessageBarCtrl --&gt;
 * &lt; bean id=&quot;messageBarCtrl&quot; class=&quot;de.forsthaus.webui.util.MessageBarCtrl&quot;
 *    scope=&quot;prototype&quot;&gt;
 * &lt; /bean&gt;
 * &lt;/pre&gt;
 *
 * 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 = &quot;&quot;;
	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(&quot;testEventQueue&quot;, 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(&quot;tb&quot;)).setValue(getMsg());
					MessageBarCtrl.this.btnOpenMsg.setImage(&quot;/images/icons/incoming_message1_16x16.gif&quot;);
				} else {
					((Textbox) getMsgWindow().getFellow(&quot;tb&quot;)).setValue(getMsg());
				}
			}
		});

	}

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

		final Grid grid = new Grid();
		grid.setHeight(&quot;100%&quot;);
		grid.setWidth(&quot;50px&quot;);
		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(&quot;50px&quot;);
		this.statusBarMessageIndicator.setStyle(&quot;background-color: #D6DCDE; padding: 0px&quot;);
		this.statusBarMessageIndicator.setParent(columns);
		Div div = new Div();
		div.setStyle(&quot;padding: 1px;&quot;);
		div.setParent(statusBarMessageIndicator);

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

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

			}
		});

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

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

	}

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

	public void setMsg(String msg) {
		this.msg = this.msg + &quot;\n&quot; + msg;
		// this.msg = this.msg + &quot;\n&quot; +
		// &quot;_____________________________________________________&quot; + &quot;\n&quot;;
	}

	public String getMsg() {
		return msg;
	}

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

	public Window getMsgWindow() {

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

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

			msgWindow.doOverlapped();

		}

		return msgWindow;
	}
}
</pre>
<p></code></p>
<p>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.</p>
<div class="wp-caption alignnone" style="width: 482px"><img title="show Message" src="http://www.forsthaus.de/zkoss/pics/messageBar_show.jpg" alt="window for showing the messages" width="472" height="342" /><p class="wp-caption-text">window for showing the messages</p></div>
<p>After clicking on the right icon there comes a window up for inserting the message text to send.</p>
<div class="wp-caption alignnone" style="width: 411px"><img title="send Message" src="http://www.forsthaus.de/zkoss/pics/messageBar_input.jpg" alt="window for writing and sending a message" width="401" height="195" /><p class="wp-caption-text">window for showing the messages</p></div>
<p>The code for the InputMessageTextBox looks like  this:</p>
<p><span style="text-decoration: underline;"> InputMessageTextBox.java </span></p>
<p><code>
<pre class="brush: java;">
/**
 * This class creates a modal window as a dialog in which the user &lt;br&gt;
 * can input some text. By onClosing with &lt;RETURN&gt; or Button &lt;send&gt; this
 * InputConfirmBox can return the message as a String value if not empty. &lt;br&gt;
 * In this case the returnValue is the same as the inputValue.&lt;br&gt;
 *
 * @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 = &quot;&quot;;
	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(&quot;350px&quot;);
		setHeight(&quot;150px&quot;);
		setTitle(Labels.getLabel(&quot;message.Information.PleaseInsertText&quot;));
		setId(&quot;confBox&quot;);
		setVisible(true);
		setClosable(true);
		addEventListener(&quot;onOK&quot;, new OnCloseListener());

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

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

		textbox.setWidth(&quot;98%&quot;);
		textbox.setHeight(&quot;80px&quot;);
		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(&quot;common.Send&quot;));
		btnSend.setParent(this);
		btnSend.addEventListener(&quot;onClick&quot;, 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()) + &quot; / &quot; + Labels.getLabel(&quot;common.Message.From&quot;) + &quot; &quot; + userName + &quot;:&quot; + &quot;\n&quot;;
				msg = msg + textbox.getText();
				msg = msg + &quot;\n&quot; + &quot;_____________________________________________________&quot; + &quot;\n&quot;;

				onClose();
			}
		});

		try {
			doModal();
		} catch (SuspendNotAllowedException e) {
			logger.fatal(&quot;&quot;, e);
		} catch (InterruptedException e) {
			logger.fatal(&quot;&quot;, 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;
	}

}
</pre>
<p></code></p>
<p>It&#8217;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&#8217;s account who is the receiver of the message in the MessageBarCtrl.</p>
<p>Samples are hostet in the Zksample2 project on <img alt="" src="http://sourceforge.net/sflogo.php?group_id=297404" href="http://zksample2.sourceforge.net/" title="." class="alignnone" width="88" height="31" /></p>
<p>Have fun with it.</p>
<p>Stephan Gerth<br />
Dipl.rer.pol.</p>
<hr />
PS: Help to prevent the global warming by writing cool software</p>
]]></content:encoded>
			<wfw:commentRss>http://www.forsthaus.de/blog/?feed=rss2&amp;p=579</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>How to customize a spring-security form-login. Part 5</title>
		<link>http://www.forsthaus.de/blog/?p=570</link>
		<comments>http://www.forsthaus.de/blog/?p=570#comments</comments>
		<pubDate>Mon, 02 Aug 2010 21:32:28 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[- Spring framework /                    ZK integration]]></category>

		<guid isPermaLink="false">http://www.forsthaus.de/blog/?p=570</guid>
		<description><![CDATA[Coming soon&#8230;
Samples are hostet in the Zksample2 project on 
]]></description>
			<content:encoded><![CDATA[<p>Coming soon&#8230;</p>
<p>Samples are hostet in the Zksample2 project on <img alt="" src="http://sourceforge.net/sflogo.php?group_id=297404" href="http://zksample2.sourceforge.net/" title="." class="alignnone" width="88" height="31" /></p>
]]></content:encoded>
			<wfw:commentRss>http://www.forsthaus.de/blog/?feed=rss2&amp;p=570</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>How to create a StatusBarController with the zk framework ?</title>
		<link>http://www.forsthaus.de/blog/?p=515</link>
		<comments>http://www.forsthaus.de/blog/?p=515#comments</comments>
		<pubDate>Thu, 08 Jul 2010 13:10:59 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[- ZK framework]]></category>

		<guid isPermaLink="false">http://www.forsthaus.de/blog/?p=515</guid>
		<description><![CDATA[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 [...]]]></description>
			<content:encoded><![CDATA[<p><strong>A simple statusBarController that works with the new zk5 <strong>EventQueues</strong> mechanism. </strong> </p>
<p>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 <strong>EventQueues</strong> mechanism.</p>
<p>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).</p>
<p>One way is to create the columns of the statusBar in a zul-template like this:</p>
<p><span style="text-decoration: underline;"> pieces of the zul-template </span><br />
<code>
<pre class="brush: java;">
            .  .  .
			&lt;south id=&quot;south&quot; border=&quot;none&quot; margins=&quot;1,0,0,0&quot;
				height=&quot;20px&quot; splittable=&quot;false&quot; flex=&quot;true&quot;&gt;
				&lt;div id=&quot;divSouth&quot;&gt;

					&lt;grid id=&quot;statusBarGrid&quot; fixedLayout=&quot;true&quot;
						height=&quot;20px&quot; width=&quot;100%&quot;&gt;
						&lt;columns sizable=&quot;false&quot;&gt;

							&lt;column label=&quot;User:&quot; width=&quot;10%&quot;
								style=&quot;background-color: #D6DCDE;&quot; /&gt;

							&lt;column id=&quot;statusBarColUser&quot; label=&quot;&quot;
								width=&quot;10%&quot; style=&quot;background-color: #D6DCDE;&quot; /&gt;

							&lt;column label=&quot;Office-No.:&quot; width=&quot;10%&quot;
								style=&quot;background-color: #D6DCDE;&quot; /&gt;

							&lt;column id=&quot;statusBarSelectedObject&quot;
								width=&quot;30%&quot; style=&quot;color: blue; background-color: #D6DCDE;&quot; /&gt;

							&lt;column id=&quot;statusBarAppVersion&quot;
								style=&quot;color: #FF0000; background-color: #D6DCDE;&quot; width=&quot;20%&quot; /&gt;

							&lt;column id=&quot;statusBarTableSchema&quot;
								width=&quot;20%&quot; style=&quot;color: blue; background-color: #D6DCDE;&quot;
								align=&quot;left&quot; /&gt;

						&lt;/columns&gt;
					&lt;/grid&gt;
				&lt;/div&gt;

			&lt;/south&gt;
		&lt;/borderlayout&gt;
</pre>
<p></code></p>
<p>It should looks like in this picture:<br />
<div class="wp-caption alignnone" style="width: 899px"><img alt="StatusBarController" src="http://www.forsthaus.de/zkoss/pics/statusBarCtrl.jpg" title="StatusBarController" width="600" height="110" /><p class="wp-caption-text">StatusBarController</p></div></p>
<p>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()&#8217;s or a little smaller with autowireing the components with a GenericForwardComposer. </p>
<p><span style="text-decoration: underline;"> pieces of the old java controller code </span><br />
<code>
<pre class="brush: java;">
            .  .  .
		// show the selected Customers data in the statusBar column 'statusBarSelectedObject'
		if (aCustomer != null) {
			Column aColumn = (Column) event.getPage().getFirstRoot().getFellowIfAny(&quot;statusBarSelectedObject&quot;);

			if (aColumn != null) {
				aColumn.setLabel(&quot;--&gt; &quot; + aCustomer.getName1() + &quot;, &quot; + aCustomer.getName2() + &quot;; &quot; + aCustomer.getZip() + &quot;-&quot; + aCustomer.getCity());
			}
		}
</pre>
<p></code></p>
<p>With the EventQueues mechanism ships with zk 5.x it&#8217;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  &#8216;Listeners&#8217;  for the 5 columns. Like &#8216;the same procedure as every year, James?&#8217; we create all inside a window container component so we need only one line of code in the zul-template for declaring our statusBarController.</p>
<p>The controller code looks like this:</p>
<p><span style="text-decoration: underline;"> StatusBarCtrl.java </span><br />
<code>
<pre class="brush: 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;

/**
 * =======================================================================&lt;br&gt;
 * StatusBarController. &lt;br&gt;
 * =======================================================================&lt;br&gt;
 * 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.&lt;br&gt;
 *
 * Declaration in the zul-file:&lt;br&gt;
 *
 * &lt;pre&gt;
 * &lt; borderlayout &gt;
 *   . . .
 *    &lt; !-- STATUS BAR AREA -- &gt;
 *    &lt; south id=&quot;south&quot; border=&quot;none&quot; margins=&quot;1,0,0,0&quot;
 * 		height=&quot;20px&quot; splittable=&quot;false&quot; flex=&quot;true&quot; &gt;
 * 	      &lt; div id=&quot;divSouth&quot; &gt;
 *
 *          &lt; !-- The StatusBar. Comps are created in the Controller -- &gt;
 *          &lt; window id=&quot;winStatusBar&quot; apply=&quot;${statusBarCtrl}&quot;
 *                   border=&quot;none&quot; width=&quot;100%&quot; height=&quot;100%&quot; /&gt;
 *
 *        &lt; /div &gt;
 *    &lt; /south &gt;
 *  &lt; /borderlayout &gt;
 * &lt;/pre&gt;
 *
 * call in java to actualize a columns label:
 *
 * &lt;pre&gt;
 * EventQueues.lookup(&amp;quot;userNameEventQueue&amp;quot;, EventQueues.DESKTOP, true).publish(new Event(&amp;quot;onChangeSelectedObject&amp;quot;, null, &amp;quot;new Value&amp;quot;));
 * &lt;/pre&gt;
 *
 * Spring bean declaration:
 *
 * &lt;pre&gt;
 * &lt; !-- StatusBarController --&gt;
 * &lt; bean id=&quot;statusBarCtrl&quot; class=&quot;de.forsthaus.webui.util.StatusBarCtrl&quot;
 *    scope=&quot;prototype&quot;&gt;
 * &lt; /bean&gt;
 * &lt;/pre&gt;
 *
 * 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(&quot;common.User&quot;) + &quot;: &quot;;
	private String _labelOfficeId = Labels.getLabel(&quot;common.OfficeId&quot;) + &quot;: &quot;;
	private String _labelSelectedObject = Labels.getLabel(&quot;common.SelectedSign&quot;) + &quot;: &quot;;
	private String _labelAppVersion = Labels.getLabel(&quot;common.Version&quot;) + &quot;: &quot;;
	private String _labelTableSchema = Labels.getLabel(&quot;common.TableSchema&quot;) + &quot;: &quot;;

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

		if (logger.isDebugEnabled()) {
			logger.debug(&quot;--&gt; super()&quot;);
		}
	}

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

		// Listener for Username
		EventQueues.lookup(&quot;userNameEventQueue&quot;, 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(&quot;officeIdEventQueue&quot;, 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(&quot;selectedObjectEventQueue&quot;, 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(&quot;appVersionEventQueue&quot;, 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(&quot;tableSchemaEventQueue&quot;, 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(&quot;100%&quot;);
		grid.setWidth(&quot;100%&quot;);
		grid.setParent(winStatusBar);

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

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

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

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

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

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

	}
}
</pre>
<p></code></p>
<p>We can now add the statusBar in our zul-template with a single line of code:</p>
<p><window id="winStatusBar" apply="${statusBarCtrl}"	border="none" width="100%" height="100%" /></p>
<p>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:</p>
<p><span style="text-decoration: underline;"> pieces of the zul-template </span><br />
<code>
<pre class="brush: java;">
   .  .  .
		    &lt;!-- STATUS BAR AREA --&gt;
			&lt;south id=&quot;south&quot; border=&quot;none&quot; margins=&quot;1,0,0,0&quot;
				height=&quot;20px&quot; splittable=&quot;false&quot; flex=&quot;true&quot;&gt;
				&lt;div id=&quot;divSouth&quot;&gt;

					&lt;!-- The StatusBar. Comps are created in the Controller --&gt;
					&lt;window id=&quot;winStatusBar&quot; apply=&quot;${statusBarCtrl}&quot; border=&quot;none&quot; width=&quot;100%&quot; height=&quot;100%&quot; /&gt;

				&lt;/div&gt;
			&lt;/south&gt;
		&lt;/borderlayout&gt;
   .  .  .
</pre>
<p></code></p>
<p>At last we have a look on how we call such a &#8216;listener&#8217; . 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 <strong>.publish()</strong> method will send the events data to the EventQueues listener and there&#8217;s the code running that we have defined in the onEvent() method.  The final code looks like here:</p>
<p><span style="text-decoration: underline;">calling the EventQueue </span><br />
<code>
<pre class="brush: java;">

	public void onSelect$listBoxCustomer(Event event) {

		Customer aCustomer = getSelectedCustomer();

		if (aCustomer != null) {

         		// show the objects data in the statusBar
		        EventQueues.lookup(&quot;selectedObjectEventQueue&quot;, EventQueues.DESKTOP, true).publish(new Event(&quot;onChangeSelectedObject&quot;, null, aCustomer.getName1()));
		}
	}
</pre>
<p></code></p>
<p>Samples are hostet in the Zksample2 project on <img alt="" src="http://sourceforge.net/sflogo.php?group_id=297404" href="http://zksample2.sourceforge.net/" title="." class="alignnone" width="88" height="31" /></p>
<p>Have fun with it.</p>
<p>Stephan Gerth</p>
<p>Dipl.rer.pol.</p>
<hr />
PS: Help to prevent the global warming by writing cool software</p>
]]></content:encoded>
			<wfw:commentRss>http://www.forsthaus.de/blog/?feed=rss2&amp;p=515</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>How to customize a spring-security form-login. Part 4</title>
		<link>http://www.forsthaus.de/blog/?p=490</link>
		<comments>http://www.forsthaus.de/blog/?p=490#comments</comments>
		<pubDate>Tue, 06 Jul 2010 09:52:59 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[- Spring framework /                    ZK integration]]></category>

		<guid isPermaLink="false">http://www.forsthaus.de/blog/?p=490</guid>
		<description><![CDATA[An article from my zk integration series.
part 1
part 2
part 3
part 5
AuthenticationSuccessHandler.java
Handles the workflow after a successful authentication. It extends from SimpleUrlAuthenticationSuccessHandler in which we can configure a default URL. There the successful authenticated users can be sent to.
 AuthenticationSuccessHandler.java 


public class MyAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {

	private transient static final Logger logger = Logger.getLogger(MyAuthenticationSuccessHandler.class);

	@Override
	public void onAuthenticationSuccess(HttpServletRequest request, [...]]]></description>
			<content:encoded><![CDATA[<p><strong>An article from my zk integration series.</strong></p>
<p><a href="http://www.forsthaus.de/blog/?p=397">part 1</a><br />
<a href="http://www.forsthaus.de/blog/?p=429">part 2</a><br />
<a href="http://www.forsthaus.de/blog/?p=479">part 3</a><br />
<a href="http://www.forsthaus.de/blog/?p=570">part 5</a></p>
<p><em>AuthenticationSuccessHandler.java</em><br />
Handles the workflow after a successful authentication. It extends from SimpleUrlAuthenticationSuccessHandler in which we can configure a default URL. There the successful authenticated users can be sent to.</p>
<p><span style="text-decoration: underline;"> AuthenticationSuccessHandler.java </span><br />
<code>
<pre class="brush: java;">
public class MyAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {

	private transient static final Logger logger = Logger.getLogger(MyAuthenticationSuccessHandler.class);

	@Override
	public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {

		if (logger.isDebugEnabled()) {
			logger.debug(&quot;MyAuthenticationSuccessHandler&quot;);
			logger.debug(request.getContextPath());
			logger.debug(getDefaultTargetUrl());
			logger.debug(request.getContextPath() + getDefaultTargetUrl());
			logger.debug(&quot;getPrincipal() : &quot; + authentication.getPrincipal().toString());
			logger.debug(&quot;getName() : &quot; + authentication.getName());
			logger.debug(&quot;getCredentials() : &quot; + authentication.getCredentials());

			Collection&lt;GrantedAuthority&gt; col = authentication.getAuthorities();

			logger.debug(&quot;getAuthorities() COUNT : &quot; + col.size());
			int i = 0;
			for (GrantedAuthority grantedAuthority : col) {
				++i;
				logger.debug(&quot;getAuthorities()&quot; + i + &quot; : &quot; + grantedAuthority.getAuthority().toString());
			}
			logger.debug(&quot;isAuthenticated : &quot; + authentication.isAuthenticated());
		}

		// redirect the user to the configured URL
		response.sendRedirect(request.getContextPath() + getDefaultTargetUrl());
	}
}
</pre>
<p></code></p>
<p>Part 5 of this article you can read <a href="http://www.forsthaus.de/blog/?p=570">here</a>.</p>
<p>Samples are hostet in the Zksample2 project on <img alt="" src="http://sourceforge.net/sflogo.php?group_id=297404" href="http://zksample2.sourceforge.net/" title="." class="alignnone" width="88" height="31" /></p>
<p>Have fun with it.</p>
<p>Stephan Gerth</p>
<p>Dipl.rer.pol.</p>
<hr />
PS: Help to prevent the global warming by writing cool software</p>
]]></content:encoded>
			<wfw:commentRss>http://www.forsthaus.de/blog/?feed=rss2&amp;p=490</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>How to customize a spring-security form-login. Part 3</title>
		<link>http://www.forsthaus.de/blog/?p=479</link>
		<comments>http://www.forsthaus.de/blog/?p=479#comments</comments>
		<pubDate>Mon, 05 Jul 2010 09:52:45 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[- Spring framework /                    ZK integration]]></category>

		<guid isPermaLink="false">http://www.forsthaus.de/blog/?p=479</guid>
		<description><![CDATA[An article from my zk integration series.
part 1
part 2
part 4
part 5
AbstractUserDetailsAuthenticationProvider.java
The method additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordTenantAuthenticationToken authentication) allow us additional checks for a returned UserDetails. We adapt it only to our UsernamePasswordTenantAuthenticationToken.
 AbstractUserDetailsAuthenticationProvider.java 


public abstract class MyAbstractUserDetailsAuthenticationProvider implements AuthenticationProvider, InitializingBean, MessageSourceAware {
	// ~ Instance fields
	// ================================================================================================

	protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
	private UserCache userCache = new NullUserCache();
	private boolean [...]]]></description>
			<content:encoded><![CDATA[<p><strong>An article from my zk integration series.</strong></p>
<p><a href="http://www.forsthaus.de/blog/?p=397">part 1</a><br />
<a href="http://www.forsthaus.de/blog/?p=429">part 2</a><br />
<a href="http://www.forsthaus.de/blog/?p=490">part 4</a><br />
<a href="http://www.forsthaus.de/blog/?p=570">part 5</a></p>
<p><em>AbstractUserDetailsAuthenticationProvider.java</em><br />
The method additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordTenantAuthenticationToken authentication) allow us additional checks for a returned UserDetails. We adapt it only to our UsernamePasswordTenantAuthenticationToken.</p>
<p><span style="text-decoration: underline;"> AbstractUserDetailsAuthenticationProvider.java </span><br />
<code>
<pre class="brush: java;">
public abstract class MyAbstractUserDetailsAuthenticationProvider implements AuthenticationProvider, InitializingBean, MessageSourceAware {
	// ~ Instance fields
	// ================================================================================================

	protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
	private UserCache userCache = new NullUserCache();
	private boolean forcePrincipalAsString = false;
	protected boolean hideUserNotFoundExceptions = true;
	private UserDetailsChecker preAuthenticationChecks = new DefaultPreAuthenticationChecks();
	private UserDetailsChecker postAuthenticationChecks = new DefaultPostAuthenticationChecks();

	// ~ Methods
	// ========================================================================================================

	/**
	 * Allows subclasses to perform any additional checks of a returned (or
	 * cached) &lt;code&gt;UserDetails&lt;/code&gt; for a given authentication request.
	 * Generally a subclass will at least compare the
	 * {@link Authentication#getCredentials()} with a
	 * {@link UserDetails#getPassword()}. If custom logic is needed to compare
	 * additional properties of &lt;code&gt;UserDetails&lt;/code&gt; and/or
	 * &lt;code&gt;UsernamePasswordAuthenticationToken&lt;/code&gt;, these should also
	 * appear in this method.
	 *
	 * @param userDetails
	 *            as retrieved from the
	 *            {@link #retrieveUser(String, UsernamePasswordAuthenticationToken)}
	 *            or &lt;code&gt;UserCache&lt;/code&gt;
	 * @param authentication
	 *            the current request that needs to be authenticated
	 *
	 * @throws AuthenticationException
	 *             AuthenticationException if the credentials could not be
	 *             validated (generally a &lt;code&gt;BadCredentialsException&lt;/code&gt;,
	 *             an &lt;code&gt;AuthenticationServiceException&lt;/code&gt;)
	 */
	protected abstract void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordTenantAuthenticationToken authentication) throws AuthenticationException;

	public final void afterPropertiesSet() throws Exception {
		Assert.notNull(this.userCache, &quot;A user cache must be set&quot;);
		Assert.notNull(this.messages, &quot;A message source must be set&quot;);
		doAfterPropertiesSet();
	}

	public Authentication authenticate(Authentication authentication) throws AuthenticationException {
		Assert.isInstanceOf(UsernamePasswordTenantAuthenticationToken.class, authentication, messages.getMessage(&quot;AbstractUserDetailsAuthenticationProvider.onlySupports&quot;,
				&quot;Only UsernamePasswordTenantAuthenticationToken is supported&quot;));

		// Determine username
		String username = (authentication.getPrincipal() == null) ? &quot;NONE_PROVIDED&quot; : authentication.getName();

		boolean cacheWasUsed = true;
		UserDetails user = this.userCache.getUserFromCache(username);

		if (user == null) {
			cacheWasUsed = false;

			try {
				user = retrieveUser(username, (UsernamePasswordTenantAuthenticationToken) authentication);
			} catch (UsernameNotFoundException notFound) {
				if (hideUserNotFoundExceptions) {
					throw new BadCredentialsException(messages.getMessage(&quot;AbstractUserDetailsAuthenticationProvider.badCredentials&quot;, &quot;Bad credentials&quot;));
				} else {
					throw notFound;
				}
			}

			Assert.notNull(user, &quot;retrieveUser returned null - a violation of the interface contract&quot;);
		}

		try {
			preAuthenticationChecks.check(user);
			additionalAuthenticationChecks(user, (UsernamePasswordTenantAuthenticationToken) authentication);
		} catch (AuthenticationException exception) {
			if (cacheWasUsed) {
				// There was a problem, so try again after checking
				// we're using latest data (i.e. not from the cache)
				cacheWasUsed = false;
				user = retrieveUser(username, (UsernamePasswordTenantAuthenticationToken) authentication);
				preAuthenticationChecks.check(user);
				additionalAuthenticationChecks(user, (UsernamePasswordTenantAuthenticationToken) authentication);
			} else {
				throw exception;
			}
		}

		postAuthenticationChecks.check(user);

		if (!cacheWasUsed) {
			this.userCache.putUserInCache(user);
		}

		Object principalToReturn = user;

		if (forcePrincipalAsString) {
			principalToReturn = user.getUsername();
		}

		return createSuccessAuthentication(principalToReturn, authentication, user);
	}

	/**
	 * Creates a successful {@link Authentication} object.
	 * &lt;p&gt;
	 * Protected so subclasses can override.
	 * &lt;/p&gt;
	 * &lt;p&gt;
	 * Subclasses will usually store the original credentials the user supplied
	 * (not salted or encoded passwords) in the returned
	 * &lt;code&gt;Authentication&lt;/code&gt; object.
	 * &lt;/p&gt;
	 *
	 * @param principal
	 *            that should be the principal in the returned object (defined
	 *            by the {@link #isForcePrincipalAsString()} method)
	 * @param authentication
	 *            that was presented to the provider for validation
	 * @param user
	 *            that was loaded by the implementation
	 *
	 * @return the successful authentication token
	 */
	protected Authentication createSuccessAuthentication(Object principal, Authentication authentication, UserDetails user) {
		// Ensure we return the original credentials the user supplied,
		// so subsequent attempts are successful even with encoded passwords.
		// Also ensure we return the original getDetails(), so that future
		// authentication events after cache expiry contain the details

		// OLD
		// UsernamePasswordTenantAuthenticationToken result = new
		// UsernamePasswordTenantAuthenticationToken(principal,
		// authentication.getCredentials(), user.getAuthorities());
		UsernamePasswordTenantAuthenticationToken result = new UsernamePasswordTenantAuthenticationToken(principal, authentication.getCredentials(), user.getAuthorities(),
				((UsernamePasswordTenantAuthenticationToken) authentication).getTenantId());
		result.setDetails(authentication.getDetails());

		return result;
	}

	protected void doAfterPropertiesSet() throws Exception {
	}

	public UserCache getUserCache() {
		return userCache;
	}

	public boolean isForcePrincipalAsString() {
		return forcePrincipalAsString;
	}

	public boolean isHideUserNotFoundExceptions() {
		return hideUserNotFoundExceptions;
	}

	/**
	 * Allows subclasses to actually retrieve the &lt;code&gt;UserDetails&lt;/code&gt; from
	 * an implementation-specific location, with the option of throwing an
	 * &lt;code&gt;AuthenticationException&lt;/code&gt; immediately if the presented
	 * credentials are incorrect (this is especially useful if it is necessary
	 * to bind to a resource as the user in order to obtain or generate a
	 * &lt;code&gt;UserDetails&lt;/code&gt;).
	 * &lt;p&gt;
	 * Subclasses are not required to perform any caching, as the
	 * &lt;code&gt;AbstractUserDetailsAuthenticationProvider&lt;/code&gt; will by default
	 * cache the &lt;code&gt;UserDetails&lt;/code&gt;. The caching of
	 * &lt;code&gt;UserDetails&lt;/code&gt; does present additional complexity as this means
	 * subsequent requests that rely on the cache will need to still have their
	 * credentials validated, even if the correctness of credentials was assured
	 * by subclasses adopting a binding-based strategy in this method.
	 * Accordingly it is important that subclasses either disable caching (if
	 * they want to ensure that this method is the only method that is capable
	 * of authenticating a request, as no &lt;code&gt;UserDetails&lt;/code&gt; will ever be
	 * cached) or ensure subclasses implement
	 * {@link #additionalAuthenticationChecks(UserDetails, UsernamePasswordAuthenticationToken)}
	 * to compare the credentials of a cached &lt;code&gt;UserDetails&lt;/code&gt; with
	 * subsequent authentication requests.
	 * &lt;/p&gt;
	 * &lt;p&gt;
	 * Most of the time subclasses will not perform credentials inspection in
	 * this method, instead performing it in
	 * {@link #additionalAuthenticationChecks(UserDetails, UsernamePasswordAuthenticationToken)}
	 * so that code related to credentials validation need not be duplicated
	 * across two methods.
	 * &lt;/p&gt;
	 *
	 * @param username
	 *            The username to retrieve
	 * @param authentication
	 *            The authentication request, which subclasses &lt;em&gt;may&lt;/em&gt; need
	 *            to perform a binding-based retrieval of the
	 *            &lt;code&gt;UserDetails&lt;/code&gt;
	 *
	 * @return the user information (never &lt;code&gt;null&lt;/code&gt; - instead an
	 *         exception should the thrown)
	 *
	 * @throws AuthenticationException
	 *             if the credentials could not be validated (generally a
	 *             &lt;code&gt;BadCredentialsException&lt;/code&gt;, an
	 *             &lt;code&gt;AuthenticationServiceException&lt;/code&gt; or
	 *             &lt;code&gt;UsernameNotFoundException&lt;/code&gt;)
	 */
	protected abstract UserDetails retrieveUser(String username, UsernamePasswordTenantAuthenticationToken authentication) throws AuthenticationException;

	public void setForcePrincipalAsString(boolean forcePrincipalAsString) {
		this.forcePrincipalAsString = forcePrincipalAsString;
	}

	/**
	 * By default the &lt;code&gt;AbstractUserDetailsAuthenticationProvider&lt;/code&gt;
	 * throws a &lt;code&gt;BadCredentialsException&lt;/code&gt; if a username is not found
	 * or the password is incorrect. Setting this property to &lt;code&gt;false&lt;/code&gt;
	 * will cause &lt;code&gt;UsernameNotFoundException&lt;/code&gt;s to be thrown instead
	 * for the former. Note this is considered less secure than throwing
	 * &lt;code&gt;BadCredentialsException&lt;/code&gt; for both exceptions.
	 *
	 * @param hideUserNotFoundExceptions
	 *            set to &lt;code&gt;false&lt;/code&gt; if you wish
	 *            &lt;code&gt;UsernameNotFoundException&lt;/code&gt;s to be thrown instead
	 *            of the non-specific &lt;code&gt;BadCredentialsException&lt;/code&gt;
	 *            (defaults to &lt;code&gt;true&lt;/code&gt;)
	 */
	public void setHideUserNotFoundExceptions(boolean hideUserNotFoundExceptions) {
		this.hideUserNotFoundExceptions = hideUserNotFoundExceptions;
	}

	public void setMessageSource(MessageSource messageSource) {
		this.messages = new MessageSourceAccessor(messageSource);
	}

	public void setUserCache(UserCache userCache) {
		this.userCache = userCache;
	}

	public boolean supports(Class&lt;? extends Object&gt; authentication) {
		return (UsernamePasswordTenantAuthenticationToken.class.isAssignableFrom(authentication));
	}

	protected UserDetailsChecker getPreAuthenticationChecks() {
		return preAuthenticationChecks;
	}

	/**
	 * Sets the policy will be used to verify the status of the loaded
	 * &lt;tt&gt;UserDetails&lt;/tt&gt; &lt;em&gt;before&lt;/em&gt; validation of the credentials takes
	 * place.
	 *
	 * @param preAuthenticationChecks
	 *            strategy to be invoked prior to authentication.
	 */
	public void setPreAuthenticationChecks(UserDetailsChecker preAuthenticationChecks) {
		this.preAuthenticationChecks = preAuthenticationChecks;
	}

	protected UserDetailsChecker getPostAuthenticationChecks() {
		return postAuthenticationChecks;
	}

	public void setPostAuthenticationChecks(UserDetailsChecker postAuthenticationChecks) {
		this.postAuthenticationChecks = postAuthenticationChecks;
	}

	private class DefaultPreAuthenticationChecks implements UserDetailsChecker {
		public void check(UserDetails user) {
			if (!user.isAccountNonLocked()) {
				throw new LockedException(messages.getMessage(&quot;AbstractUserDetailsAuthenticationProvider.locked&quot;, &quot;User account is locked&quot;), user);
			}

			if (!user.isEnabled()) {
				throw new DisabledException(messages.getMessage(&quot;AbstractUserDetailsAuthenticationProvider.disabled&quot;, &quot;User is disabled&quot;), user);
			}

			if (!user.isAccountNonExpired()) {
				throw new AccountExpiredException(messages.getMessage(&quot;AbstractUserDetailsAuthenticationProvider.expired&quot;, &quot;User account has expired&quot;), user);
			}
		}
	}

	private class DefaultPostAuthenticationChecks implements UserDetailsChecker {
		public void check(UserDetails user) {
			if (!user.isCredentialsNonExpired()) {
				throw new CredentialsExpiredException(messages.getMessage(&quot;AbstractUserDetailsAuthenticationProvider.credentialsExpired&quot;, &quot;User credentials have expired&quot;), user);
			}
		}
	}
}
</pre>
<p></code></p>
<p><em>MyDaoAuthenticationProvider.java</em><br />
An implementation of an AuthenticationProvider that retrieves the user details from an UserDetailsService.</p>
<p><span style="text-decoration: underline;"> MyDaoAuthenticationProvider .java </span><br />
<code>
<pre class="brush: java;">
public class MyDaoAuthenticationProvider extends MyAbstractUserDetailsAuthenticationProvider {

	// ~ Instance fields
	// ================================================================================================

	private PasswordEncoder passwordEncoder = new PlaintextPasswordEncoder();

	private SaltSource saltSource;

	private UserDetailsService userDetailsService;

	private boolean includeDetailsObject = true;

	// ~ Methods
	// ========================================================================================================

	protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordTenantAuthenticationToken authentication) throws AuthenticationException {
		Object salt = null;

		if (this.saltSource != null) {
			salt = this.saltSource.getSalt(userDetails);
		}

		if (authentication.getCredentials() == null) {
			throw new BadCredentialsException(messages.getMessage(&quot;AbstractUserDetailsAuthenticationProvider.badCredentials&quot;, &quot;Bad credentials&quot;), includeDetailsObject ? userDetails : null);
		}

		String presentedPassword = authentication.getCredentials().toString();

		if (!passwordEncoder.isPasswordValid(userDetails.getPassword(), presentedPassword, salt)) {
			throw new BadCredentialsException(messages.getMessage(&quot;AbstractUserDetailsAuthenticationProvider.badCredentials&quot;, &quot;Bad credentials&quot;), includeDetailsObject ? userDetails : null);
		}
	}

	protected void doAfterPropertiesSet() throws Exception {
		Assert.notNull(this.userDetailsService, &quot;A UserDetailsService must be set&quot;);
	}

	protected final UserDetails retrieveUser(String username, UsernamePasswordTenantAuthenticationToken authentication) throws AuthenticationException {
		UserDetails loadedUser;

		try {
			loadedUser = this.getUserDetailsService().loadUserByUsername(username + &quot;/&quot; + authentication.getTenantId());
		} catch (DataAccessException repositoryProblem) {
			throw new AuthenticationServiceException(repositoryProblem.getMessage(), repositoryProblem);
		}

		if (loadedUser == null) {
			throw new AuthenticationServiceException(&quot;UserDetailsService returned null, which is an interface contract violation&quot;);
		}
		return loadedUser;
	}

	/**
	 * Sets the PasswordEncoder instance to be used to encode and validate
	 * passwords. If not set, {@link PlaintextPasswordEncoder} will be used by
	 * default.
	 *
	 * @param passwordEncoder
	 *            The passwordEncoder to use
	 */
	public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
		this.passwordEncoder = passwordEncoder;
	}

	protected PasswordEncoder getPasswordEncoder() {
		return passwordEncoder;
	}

	/**
	 * The source of salts to use when decoding passwords. &lt;code&gt;null&lt;/code&gt; is
	 * a valid value, meaning the &lt;code&gt;DaoAuthenticationProvider&lt;/code&gt; will
	 * present &lt;code&gt;null&lt;/code&gt; to the relevant &lt;code&gt;PasswordEncoder&lt;/code&gt;.
	 *
	 * @param saltSource
	 *            to use when attempting to decode passwords via the
	 *            &lt;code&gt;PasswordEncoder&lt;/code&gt;
	 */
	public void setSaltSource(SaltSource saltSource) {
		this.saltSource = saltSource;
	}

	protected SaltSource getSaltSource() {
		return saltSource;
	}

	public void setUserDetailsService(UserDetailsService userDetailsService) {
		this.userDetailsService = userDetailsService;
	}

	protected UserDetailsService getUserDetailsService() {
		return userDetailsService;
	}

	protected boolean isIncludeDetailsObject() {
		return includeDetailsObject;
	}

	/**
	 * Determines whether the UserDetails will be included in the
	 * &lt;tt&gt;extraInformation&lt;/tt&gt; field of a thrown BadCredentialsException.
	 * Defaults to true, but can be set to false if the exception will be used
	 * with a remoting protocol, for example.
	 *
	 * @deprecated use
	 *             {@link org.springframework.security.authentication.ProviderManager#setClearExtraInformation(boolean)}
	 */
	public void setIncludeDetailsObject(boolean includeDetailsObject) {
		this.includeDetailsObject = includeDetailsObject;
	}
}
</pre>
<p></code></p>
<p>Part 4 of this article you can read <a href="http://www.forsthaus.de/blog/?p=490">here</a>.</p>
<p>Samples are hostet in the Zksample2 project on <img alt="" src="http://sourceforge.net/sflogo.php?group_id=297404" href="http://zksample2.sourceforge.net/" title="." class="alignnone" width="88" height="31" /></p>
<p>Have fun with it.</p>
<p>Stephan Gerth</p>
<p>Dipl.rer.pol.</p>
<hr />
PS: Help to prevent the global warming by writing cool software</p>
]]></content:encoded>
			<wfw:commentRss>http://www.forsthaus.de/blog/?feed=rss2&amp;p=479</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>How to customize a spring-security form-login. Part 2</title>
		<link>http://www.forsthaus.de/blog/?p=429</link>
		<comments>http://www.forsthaus.de/blog/?p=429#comments</comments>
		<pubDate>Fri, 02 Jul 2010 19:57:44 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[- Spring framework /                    ZK integration]]></category>

		<guid isPermaLink="false">http://www.forsthaus.de/blog/?p=429</guid>
		<description><![CDATA[An article from my zk integration series.
part 1
part 3
part 4
part 5
Bellow are the used main classes for a spring-security form-login:
UsernamePasswordAuthenticationToken.java: 
This class is an authentication implementation that represents a simple username and password. We modifiy it for the TenantId and change the name to UsernamePasswordTenantAuthenticationToken.java
 UsernamePasswordTenantAuthenticationToken.java 


@SuppressWarnings(&#34;serial&#34;)
public class UsernamePasswordTenantAuthenticationToken extends AbstractAuthenticationToken {
	// ~ Instance fields
	// [...]]]></description>
			<content:encoded><![CDATA[<p><strong>An article from my zk integration series.</strong></p>
<p><a href="http://www.forsthaus.de/blog/?p=397">part 1</a><br />
<a href="http://www.forsthaus.de/blog/?p=479">part 3</a><br />
<a href="http://www.forsthaus.de/blog/?p=490">part 4</a><br />
<a href="http://www.forsthaus.de/blog/?p=570">part 5</a></p>
<p>Bellow are the used main classes for a spring-security form-login:</p>
<p><em>UsernamePasswordAuthenticationToken.java: </em><br />
This class is an authentication implementation that represents a simple username and password. We modifiy it for the TenantId and change the name to UsernamePasswordTenantAuthenticationToken.java</p>
<p><span style="text-decoration: underline;"> UsernamePasswordTenantAuthenticationToken.java </span><br />
<code>
<pre class="brush: java;">
@SuppressWarnings(&quot;serial&quot;)
public class UsernamePasswordTenantAuthenticationToken extends AbstractAuthenticationToken {
	// ~ Instance fields
	// ================================================================================================

	private final Object credentials;
	private final Object principal;
	private final Object tenantId;

	// ~ Constructors
	// ===================================================================================================

	/**
	 * This constructor can be safely used by any code that wishes to create a
	 * &lt;code&gt;UsernamePasswordAuthenticationToken&lt;/code&gt;, as the
	 * {@link #isAuthenticated()} will return &lt;code&gt;false&lt;/code&gt;.
	 *
	 */
	public UsernamePasswordTenantAuthenticationToken(Object principal, Object credentials, Object tenantId) {
		super(null);
		this.principal = principal;
		this.credentials = credentials;
		this.tenantId = tenantId;
		setAuthenticated(false);
	}

	/**
	 * @deprecated use the list of authorities version
	 */
	public UsernamePasswordTenantAuthenticationToken(Object principal, Object credentials, GrantedAuthority[] authorities) {
		this(principal, credentials, Arrays.asList(authorities));
	}

	/**
	 * This constructor should only be used by
	 * &lt;code&gt;AuthenticationManager&lt;/code&gt; or &lt;code&gt;AuthenticationProvider&lt;/code&gt;
	 * implementations that are satisfied with producing a trusted (i.e.
	 * {@link #isAuthenticated()} = &lt;code&gt;true&lt;/code&gt;) authentication token.
	 *
	 * @param principal
	 * @param credentials
	 * @param authorities
	 */
	public UsernamePasswordTenantAuthenticationToken(Object principal, Object credentials, Collection&lt;GrantedAuthority&gt; authorities, Object tenantId) {
		super(authorities);
		this.principal = principal;
		this.credentials = credentials;
		this.tenantId = tenantId;
		super.setAuthenticated(true); // must use super, as we override
	}

	// ~ Methods
	// ========================================================================================================

	public Object getCredentials() {
		return this.credentials;
	}

	public Object getPrincipal() {
		return this.principal;
	}

	public Object getTenantId() {
		return this.tenantId;
	}

	public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
		if (isAuthenticated) {
			throw new IllegalArgumentException(&quot;Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead&quot;);
		}

		super.setAuthenticated(false);
	}
}
</pre>
<p></code></p>
<p><em>UserPasswordAuthenticationFilter.java</em><br />
This class processes the submission of an authentication form, means our ZKLoginDialog . This filter responds per default to the /j_spring_security_check URL.</p>
<p><span style="text-decoration: underline;"> UserPasswordAuthenticationFilter.java </span><br />
<code>
<pre class="brush: java;">
public class UserPasswordTenantAuthenticationFilter extends AbstractAuthenticationProcessingFilter {

	// ~ Static fields/initializers
	// =====================================================================================

	public static final String SPRING_SECURITY_FORM_USERNAME_KEY = &quot;j_username&quot;;
	public static final String SPRING_SECURITY_FORM_PASSWORD_KEY = &quot;j_password&quot;;
	public static final String SPRING_SECURITY_FORM_TENANTID_KEY = &quot;j_tenantid&quot;;
	public static final String SPRING_SECURITY_LAST_USERNAME_KEY = &quot;SPRING_SECURITY_LAST_USERNAME&quot;;

	private String usernameParameter = SPRING_SECURITY_FORM_USERNAME_KEY;
	private String passwordParameter = SPRING_SECURITY_FORM_PASSWORD_KEY;
	private String tenantParameter = SPRING_SECURITY_FORM_TENANTID_KEY;
	private boolean postOnly = true;

	// ~ Constructors
	// ===================================================================================================

	public UserPasswordTenantAuthenticationFilter() {
		super(&quot;/j_spring_security_check&quot;);
	}

	// ~ Methods
	// ========================================================================================================

	public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
		if (postOnly &amp;&amp; !request.getMethod().equals(&quot;POST&quot;)) {
			throw new AuthenticationServiceException(&quot;Authentication method not supported: &quot; + request.getMethod());
		}

		String username = obtainUsername(request);
		String password = obtainPassword(request);
		String tenantId = obtainTenantId(request);

		if (username == null) {
			username = &quot;&quot;;
		}

		if (password == null) {
			password = &quot;&quot;;
		}

		if (tenantId == null) {
			tenantId = &quot;&quot;;
		}

		username = username.trim();
		tenantId = tenantId.trim();

		UsernamePasswordTenantAuthenticationToken authRequest = new UsernamePasswordTenantAuthenticationToken(username, password, null, tenantId);

		// Place the last username attempted into HttpSession for views
		HttpSession session = request.getSession(false);

		if (session != null || getAllowSessionCreation()) {
			request.getSession().setAttribute(SPRING_SECURITY_LAST_USERNAME_KEY, TextEscapeUtils.escapeEntities(username));
		}

		// Allow subclasses to set the &quot;details&quot; property
		setDetails(request, authRequest);

		return this.getAuthenticationManager().authenticate(authRequest);
	}

	/**
	 * Enables subclasses to override the composition of the password, such as
	 * by including additional values and a separator.
	 * &lt;p&gt;
	 * This might be used for example if a postcode/zipcode was required in
	 * addition to the password. A delimiter such as a pipe (|) should be used
	 * to separate the password and extended value(s). The
	 * &lt;code&gt;AuthenticationDao&lt;/code&gt; will need to generate the expected
	 * password in a corresponding manner.
	 * &lt;/p&gt;
	 *
	 * @param request
	 *            so that request attributes can be retrieved
	 *
	 * @return the password that will be presented in the
	 *         &lt;code&gt;Authentication&lt;/code&gt; request token to the
	 *         &lt;code&gt;AuthenticationManager&lt;/code&gt;
	 */
	protected String obtainPassword(HttpServletRequest request) {
		return request.getParameter(passwordParameter);
	}

	/**
	 * Enables subclasses to override the composition of the username, such as
	 * by including additional values and a separator.
	 *
	 * @param request
	 *            so that request attributes can be retrieved
	 *
	 * @return the username that will be presented in the
	 *         &lt;code&gt;Authentication&lt;/code&gt; request token to the
	 *         &lt;code&gt;AuthenticationManager&lt;/code&gt;
	 */
	protected String obtainUsername(HttpServletRequest request) {
		return request.getParameter(usernameParameter);
	}

	/**
	 * Enables subclasses to override the composition of the tenantID, such as
	 * by including additional values and a separator.
	 *
	 * @param request
	 *            so that request attributes can be retrieved
	 *
	 * @return the tenantID that will be presented in the
	 *         &lt;code&gt;Authentication&lt;/code&gt; request token to the
	 *         &lt;code&gt;AuthenticationManager&lt;/code&gt;
	 */
	protected String obtainTenantId(HttpServletRequest request) {
		return request.getParameter(tenantParameter);
	}

	/**
	 * Provided so that subclasses may configure what is put into the
	 * authentication request's details property.
	 *
	 * @param request
	 *            that an authentication request is being created for
	 * @param authRequest
	 *            the authentication request object that should have its details
	 *            set
	 */
	protected void setDetails(HttpServletRequest request, UsernamePasswordTenantAuthenticationToken authRequest) {
		authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
	}

	/**
	 * Sets the parameter name which will be used to obtain the username from
	 * the login request.
	 *
	 * @param usernameParameter
	 *            the parameter name. Defaults to &quot;j_username&quot;.
	 */
	public void setUsernameParameter(String usernameParameter) {
		Assert.hasText(usernameParameter, &quot;Username parameter must not be empty or null&quot;);
		this.usernameParameter = usernameParameter;
	}

	/**
	 * Sets the parameter name which will be used to obtain the password from
	 * the login request..
	 *
	 * @param passwordParameter
	 *            the parameter name. Defaults to &quot;j_password&quot;.
	 */
	public void setPasswordParameter(String passwordParameter) {
		Assert.hasText(passwordParameter, &quot;Password parameter must not be empty or null&quot;);
		this.passwordParameter = passwordParameter;
	}

	/**
	 * Sets the parameter name which will be used to obtain the password from
	 * the login request..
	 *
	 * @param passwordParameter
	 *            the parameter name. Defaults to &quot;j_password&quot;.
	 */
	public void setTenantIdParameter(String tenantParameter) {
		Assert.hasText(tenantParameter, &quot;Tenant ID parameter must not be empty or null&quot;);
		this.tenantParameter = tenantParameter;
	}

	/**
	 * Defines whether only HTTP POST requests will be allowed by this filter.
	 * If set to true, and an authentication request is received which is not a
	 * POST request, an exception will be raised immediately and authentication
	 * will not be attempted. The &lt;tt&gt;unsuccessfulAuthentication()&lt;/tt&gt; method
	 * will be called as if handling a failed authentication.
	 * &lt;p&gt;
	 * Defaults to &lt;tt&gt;true&lt;/tt&gt; but may be overridden by subclasses.
	 */
	public void setPostOnly(boolean postOnly) {
		this.postOnly = postOnly;
	}

	public final String getUsernameParameter() {
		return usernameParameter;
	}

	public final String getPasswordParameter() {
		return passwordParameter;
	}

	public final String getTenantParameter() {
		return tenantParameter;
	}
}
</pre>
<p></code></p>
<p>Part 3 of this article you can read <a href="http://www.forsthaus.de/blog/?p=479">here</a>.</p>
<p>Samples are hostet in the Zksample2 project on <img alt="" src="http://sourceforge.net/sflogo.php?group_id=297404" href="http://zksample2.sourceforge.net/" title="." class="alignnone" width="88" height="31" /></p>
<p>Have fun with it.</p>
<p>Stephan Gerth</p>
<p>Dipl.rer.pol.</p>
<hr />
PS: Help to prevent the global warming by writing cool software</p>
]]></content:encoded>
			<wfw:commentRss>http://www.forsthaus.de/blog/?feed=rss2&amp;p=429</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>How to customize a spring-security form-login. Part 1</title>
		<link>http://www.forsthaus.de/blog/?p=397</link>
		<comments>http://www.forsthaus.de/blog/?p=397#comments</comments>
		<pubDate>Thu, 01 Jul 2010 14:45:48 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[- Spring framework /                    ZK integration]]></category>

		<guid isPermaLink="false">http://www.forsthaus.de/blog/?p=397</guid>
		<description><![CDATA[An article from my zk integration series.
part 2
part 3
part 4
part 5
For a spring-security 3.0.2 managed project i need a third parameter in the login dialog. This third parameter should represent a tenant id for a multi-tenant application. The logic should lookup in the tenant administrations database for the used schema name in which the tenants [...]]]></description>
			<content:encoded><![CDATA[<p><strong>An article from my zk integration series.</strong></p>
<p><a href="http://www.forsthaus.de/blog/?p=429">part 2</a><br />
<a href="http://www.forsthaus.de/blog/?p=479">part 3</a><br />
<a href="http://www.forsthaus.de/blog/?p=490">part 4</a><br />
<a href="http://www.forsthaus.de/blog/?p=570">part 5</a></p>
<p>For a <a href="http://static.springsource.org/spring-security/site/index.html">spring-security</a> 3.0.2 managed project i need a third parameter in the login dialog. This third parameter should represent a tenant id for a multi-tenant application. The logic should lookup in the tenant administrations database for the used schema name in which the tenants data are stored. Let me early say that the best practice not only for multi-tenant database applications is the way to separate completely the user/tenant and right data from the applications data. This separation is  a basic necessity for high scaling applications.  In doing so it&#8217;s equal if the users data are stored in a LDAP or database server.</p>
<p>Here&#8217;s an picture on how the login dialog should looks like:<br />
<div class="wp-caption alignnone" style="width: 432px"><img alt="ZKLoginDialog" src="http://www.forsthaus.de/zkoss/pics/login_4711.jpg" title="Login Dialog" width="422" height="227" /><p class="wp-caption-text">customized spring-security form-login dialog with zk framework</p></div></p>
<p><span style="text-decoration: underline;"> zkloginDialog.zul </span><br />
<code>
<pre class="brush: java;">
&lt;?page id=&quot;ZKLoginDialog&quot; title=&quot;LOGIN&quot;?&gt;
&lt;?taglib uri=&quot;http://www.zkoss.org/dsp/web/core&quot; prefix=&quot;c&quot;?&gt;
&lt;?variable-resolver class=&quot;org.zkoss.zkplus.spring.DelegatingVariableResolver&quot;?&gt;

&lt;zk xmlns=&quot;http://www.zkoss.org/2005/zul&quot;
	xmlns:h=&quot;http://www.w3.org/1999/xhtml&quot;
	xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
	xsi:schemaLocation=&quot;http://www.zkoss.org/2005/zul http://www.zkoss.org/2005/zul/zul.xsd&quot;&gt;

	&lt;style&gt;
		body { padding: 0 0; /* 0 padding on top and bottom and 0
		padding on right and left */

		&lt;!-- background image --&gt;
		background-image:
		url(${c:encodeURL('/images/templates/test/Grey_T_R.jpg')});
		background-repeat:repeat-x; }

		&lt;!-- cut the vertical borders in the rows --&gt;
		tr.z-row td.z-row-inner { border-right: 0px #CCC; }

		&lt;!-- nicer looking --&gt;
		.z-window-modal-cnt-noborder {background: none}
		.z-window-modal-cl-noborder {background: none}

		.outerGroupBox .z-groupbox-cnt {padding: 0px;}

		&lt;!-- Make Plain Grid --&gt;
		.GridLayoutNoBorder tr.z-row td.z-row-inner, tr.z-row
		.z-cell,div.z-grid { border: none; overflow: hidden; zoom: 1;
		background: white; border-top: none; border-left: none;
		border-right: none; border-bottom: none; }
	&lt;/style&gt;

	&lt;window id=&quot;loginwin&quot; border=&quot;none&quot; width=&quot;390px&quot;
		apply=&quot;de.forsthaus.webui.login.ZkLoginDialogCtrl&quot;&gt;

		&lt;groupbox mold=&quot;3d&quot; closable=&quot;false&quot; sclass=&quot;outerGroupBox&quot;
			contentStyle=&quot;background-color : white&quot;&gt;
			&lt;caption label=&quot;Login&quot; image=&quot;/images/earth2.gif&quot;
				style=&quot;font-weight: bold;&quot;&gt;

				&lt;button id=&quot;button_ZKLoginDialog_Close&quot;
					image=&quot;/images/icons/stop.gif&quot;
					tooltiptext=&quot;${c:l('button_ZKLoginDialog_Close.tooltiptext')}&quot; /&gt;
			&lt;/caption&gt;

			&lt;columnlayout
				style=&quot;background-image:url(${c:encodeURL('/images/login_151x222.jpg')}); &quot;&gt;
				&lt;columnchildren width=&quot;30%&quot; /&gt;

				&lt;columnchildren width=&quot;70%&quot;&gt;
					&lt;panel border=&quot;none&quot;&gt;
						&lt;panelchildren&gt;
							&lt;separator /&gt;
							&lt;groupbox
								if=&quot;${not empty param.login_error}&quot;&gt;
								&lt;label style=&quot;color:red&quot;
									value=&quot;Login failed. Please try again.&quot; /&gt;
								&lt;h:br /&gt;
								&lt;label style=&quot;color:red&quot;
									value=&quot;Reason: ${sessionScope.SPRING_SECURITY_LAST_EXCEPTION.message}&quot; /&gt;
								&lt;h:br /&gt;
							&lt;/groupbox&gt;

							&lt;groupbox
								style=&quot;padding-top: 5px; padding-left: 5px; &quot;&gt;
								&lt;caption label=&quot;Login&quot; /&gt;

								&lt;div&gt;
									&lt;!-- ### Spring Security action-url = j_spring_security_check  ### --&gt;
									&lt;h:form id=&quot;f&quot; name=&quot;f&quot;
										action=&quot;j_spring_security_check&quot; method=&quot;POST&quot;&gt;

										&lt;grid fixedLayout=&quot;true&quot;
											sclass=&quot;GridLayoutNoBorder&quot; style=&quot;border:0px&quot;&gt;
											&lt;columns&gt;
												&lt;column width=&quot;40%&quot; /&gt;
												&lt;column width=&quot;60%&quot; /&gt;
											&lt;/columns&gt;
											&lt;rows&gt;

												&lt;!-- TenantID --&gt;
												&lt;row&gt;
													&lt;label
														id=&quot;label_ZKLoginDialog_tenant&quot;
														value=&quot;${c:l('label_ZKLoginDialogTenant')}&quot; /&gt;
													&lt;textbox
														id=&quot;txtb_TenantId&quot; name=&quot;j_tenantid&quot; width=&quot;98%&quot; /&gt;
												&lt;/row&gt;

												&lt;!-- Username --&gt;
												&lt;row&gt;
													&lt;label
														id=&quot;label_ZKLoginDialog_user&quot;
														value=&quot;${c:l('label_ZKLoginDialogUser')}&quot; /&gt;
													&lt;textbox
														id=&quot;txtb_Username&quot; name=&quot;j_username&quot; width=&quot;98%&quot; /&gt;
												&lt;/row&gt;

												&lt;!-- Password --&gt;
												&lt;row&gt;
													&lt;label
														id=&quot;label_ZKLoginDialog_pwd&quot;
														value=&quot;${c:l('label_ZKLoginDialogPwd')}&quot; /&gt;
													&lt;textbox
														id=&quot;txtb_Password&quot; type=&quot;password&quot; name=&quot;j_password&quot;
														width=&quot;98%&quot; /&gt;
												&lt;/row&gt;

												&lt;row spans=&quot;2&quot;&gt;
													&lt;hbox&gt;
														&lt;h:input
															type=&quot;submit&quot; value=&quot;Login&quot; /&gt;
														&lt;!--
															&lt;button id=&quot;btnReset&quot;
															height=&quot;22px&quot; label=&quot;Reset&quot; /&gt;
														--&gt;
													&lt;/hbox&gt;
												&lt;/row&gt;
											&lt;/rows&gt;
										&lt;/grid&gt;
									&lt;/h:form&gt;
								&lt;/div&gt;

							&lt;/groupbox&gt;

						&lt;/panelchildren&gt;
					&lt;/panel&gt;
				&lt;/columnchildren&gt;
			&lt;/columnlayout&gt;

		&lt;/groupbox&gt;

	&lt;/window&gt;
&lt;/zk&gt;
</pre>
<p></code></p>
<p>The interesting part of this file are the three variable names: <em>j_tenantid</em>, <em>j_username</em>, <em>j_password </em>. These are submitting to the server  when  pressing the OK button .</p>
<li></li>
<p><span style="text-decoration: underline;"> ZKLoginDialogCtrl.java </span><br />
<code>
<pre class="brush: java;">
/**
 * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++&lt;br&gt;
 * Controller for the /WEB-INF/zkloginDialog.zul file.&lt;br&gt;
 * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++&lt;br&gt;
 *
 * @author bbruhns
 * @author sgerth
 */
public class ZkLoginDialogCtrl extends GenericForwardComposer implements Serializable {

	private transient final static Logger logger = Logger.getLogger(ZkLoginDialogCtrl.class);
	private static final long serialVersionUID = -71422545405325060L;

	/*
	 * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	 * All the components that are defined here and have a corresponding
	 * component with the same 'id' in the zul-file are getting autowired
     * by the 'GenericForwardComposer'.
	 * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	 */
	protected Window loginwin; // autowired
	protected Textbox txtb_Username; // autowired
	protected Textbox txtb_Password; // autowired
	protected Textbox txtb_TenantId; // autowired

	/**
	 * default constructor. &lt;br&gt;
	 */
	public ZkLoginDialogCtrl() {
		super();

		if (logger.isDebugEnabled()) {
			logger.debug(&quot;--&gt; super() &quot;);
		}
	}

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

		if (logger.isDebugEnabled()) {
			logger.debug(&quot;--&gt; &quot; + event.toString());
		}

		txtb_Username.focus(); // set the focus on UserName

		loginwin.setShadow(false);
		loginwin.doModal();
	}

	/**
	 * when the &quot;close&quot; button is clicked. &lt;br&gt;
	 *
	 * @throws IOException
	 */
	public void onClick$button_ZKLoginDialog_Close() throws IOException {

		if (logger.isDebugEnabled()) {
			logger.debug(&quot;--&gt;&quot;);
		}

		Executions.sendRedirect(&quot;/j_spring_logout&quot;);
	}

}
</pre>
<p></code></p>
<p>Ok. Back to the customizing. In this article i will not explain how spring-security works therefore&#8217;s the documentation. I will concentrate on the classes for the needed purpose. At first we have a look which classes are involved in the case of spring-security&#8217;s form-login.</p>
<p>This we will done in <a href="http://www.forsthaus.de/blog/?p=429">part 2</a> of this article.</p>
<p>Samples are hostet in the Zksample2 project on <img alt="" src="http://sourceforge.net/sflogo.php?group_id=297404" href="http://zksample2.sourceforge.net/" title="." class="alignnone" width="88" height="31" /></p>
<p>Have fun with it.</p>
<p>Stephan Gerth</p>
<p>Dipl.rer.pol.</p>
<hr />
PS: Help to prevent the global warming by writing cool software</p>
]]></content:encoded>
			<wfw:commentRss>http://www.forsthaus.de/blog/?feed=rss2&amp;p=397</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Modal search dialogs. Part 3: ExtendedSearchListBox skeleton.</title>
		<link>http://www.forsthaus.de/blog/?p=360</link>
		<comments>http://www.forsthaus.de/blog/?p=360#comments</comments>
		<pubDate>Thu, 01 Jul 2010 09:18:06 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[- ZK framework]]></category>

		<guid isPermaLink="false">http://www.forsthaus.de/blog/?p=360</guid>
		<description><![CDATA[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 [...]]]></description>
			<content:encoded><![CDATA[<p><strong>An extended modal searchBox/selectionList with paging and data limiting features which returns an object.</strong></p>
<p>As we see in <a href="http://www.forsthaus.de/blog/?p=274">part 1</a>  and <a href="http://www.forsthaus.de/blog/?p=340">part 2</a> 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. </p>
<p>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 &#8216;like&#8217; keyword, so that every record comes back where in their field &#8216;Description&#8217; i.e. the signs &#8216;<em>ar</em>&#8216; 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.</p>
<p>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&#8217;s size).</p>
<p><img title="ExtendedSearchListBox" src="http://www.forsthaus.de/zkoss/pics/extendedSearchListBox.jpg" alt="" width="380" height="300" /></p>
<p><span style="text-decoration: underline;"> calling in code:</span></p>
<p><code>
<pre class="brush: java;">
     Bean bean = ExtendedSearchListBox.show(parentComponent);

     if ( bean != null ) {
       // do something
       }
</pre>
<p></code></p>
<p>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.</p>
<li></li>
<p><span style="text-decoration: underline;"> The classfile:</span><br />
<code>
<pre class="brush: java;">
/**
 * 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 &lt;http://www.gnu.org/licenses/gpl.html&gt;.
 */
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 &lt;br&gt;
 * can search and select a branch object. By onClosing this box &lt;b&gt;returns&lt;/b&gt;
 * an object or null. &lt;br&gt;
 * The object can returned by selecting and clicking the OK button or by
 * DoubleClicking on an item from the list.&lt;br&gt;
 * Further the count of results can limited by manipulating the value of a table
 * field for the sql where clause.&lt;br&gt;
 * &lt;br&gt;
 * This is a basic skeleton which is extended for database paging and an
 * additionally textbox for inserting a searchparameter.&lt;br&gt;
 * &lt;br&gt;
 *
 * &lt;pre&gt;
 * call: Branch branch = BranchExtendedSearchListBox.show(parentComponent);
 * &lt;/pre&gt;
 *
 * @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(&quot;message.Information.ExtendedSearch&quot;) + &quot; / &quot; + Labels.getLabel(&quot;common.Branch&quot;);

	// 1. Listheader
	private String _listHeader1 = Labels.getLabel(&quot;common.Description&quot;);

	// 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.&lt;br&gt;
	 *
	 * @param parent
	 */
	private BranchExtendedSearchListBox(Component parent) {
		super();

		setParent(parent);

		createBox();
	}

	/**
	 * Creates the components, sets the model and show the window as modal.&lt;br&gt;
	 */
	@SuppressWarnings(&quot;unchecked&quot;)
	private void createBox() {

		// Window
		this.setWidth(String.valueOf(_width) + &quot;px&quot;);
		this.setHeight(String.valueOf(_height) + &quot;px&quot;);
		this.setTitle(_title);
		this.setVisible(true);
		this.setClosable(true);

		// Borderlayout
		Borderlayout bl = new Borderlayout();
		bl.setHeight(&quot;100%&quot;);
		bl.setWidth(&quot;100%&quot;);
		bl.setParent(this);

		Center center = new Center();
		center.setBorder(&quot;none&quot;);
		center.setFlex(true);
		center.setParent(bl);

		// Borderlayout
		Borderlayout bl2 = new Borderlayout();
		bl2.setHeight(&quot;100%&quot;);
		bl2.setWidth(&quot;100%&quot;);
		bl2.setParent(center);

		North north2 = new North();
		north2.setBorder(&quot;none&quot;);
		north2.setHeight(&quot;26px&quot;);
		north2.setParent(bl2);
		// Paging
		_paging = new Paging();
		_paging.setDetailed(true);
		_paging.addEventListener(&quot;onPaging&quot;, new OnPagingEventListener());
		_paging.setPageSize(getPageSize());
		_paging.setParent(north2);

		Center center2 = new Center();
		center2.setBorder(&quot;none&quot;);
		center2.setFlex(true);
		center2.setParent(bl2);
		// Div Center area
		Div divCenter2 = new Div();
		divCenter2.setWidth(&quot;100%&quot;);
		divCenter2.setHeight(&quot;100%&quot;);
		divCenter2.setParent(center2);

		// Listbox
		listbox = new Listbox();
		// listbox.setStyle(&quot;border: none;&quot;);
		listbox.setHeight(&quot;290px&quot;);
		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(&quot;none&quot;);
		south2.setHeight(&quot;26px&quot;);
		south2.setParent(bl2);
		// hbox for holding the Textbox + SearchButton
		Hbox hbox = new Hbox();
		hbox.setPack(&quot;stretch&quot;);
		hbox.setStyle(&quot;padding-left: 5px&quot;);
		hbox.setWidth(&quot;100%&quot;);
		hbox.setHeight(&quot;27px&quot;);
		hbox.setParent(south2);
		// textbox for inserting the search parameter
		_textbox = new Textbox();
		_textbox.setWidth(&quot;100%&quot;);
		_textbox.setMaxlength(20);
		_textbox.setParent(hbox);
		// serachButton
		_searchButton = new Button();
		_searchButton.setImage(&quot;/images/icons/search.gif&quot;);
		_searchButton.addEventListener(&quot;onClick&quot;, new OnSearchListener());
		_searchButton.setParent(hbox);

		South south = new South();
		south.setBorder(&quot;none&quot;);
		south.setHeight(&quot;30px&quot;);
		south.setParent(bl);

		Div divSouth = new Div();
		divSouth.setWidth(&quot;100%&quot;);
		divSouth.setHeight(&quot;100%&quot;);
		divSouth.setParent(south);

		Separator sep = new Separator();
		sep.setBar(true);
		sep.setOrient(&quot;horizontal&quot;);
		sep.setParent(divSouth);

		// Button
		Button btnOK = new Button();
		btnOK.setStyle(&quot;padding-left: 5px&quot;);
		btnOK.setLabel(&quot;OK&quot;);
		btnOK.addEventListener(&quot;onClick&quot;, new OnCloseListener());
		btnOK.setParent(divSouth);

		/**
		 * init the model.&lt;br&gt;
		 * The ResultObject is a helper class that holds the generic list and
		 * the totalRecord count as int value.
		 */
		ResultObject ro = getBrancheService().getAllBranchesLikeText(&quot;&quot;, 0, getPageSize());
		List&lt;Branche&gt; resultList = (List&lt;Branche&gt;) ro.getList();
		_paging.setTotalSize(ro.getTotalCount());

		// set the model
		setListModelList(new ListModelList(resultList));
		listbox.setModel(getListModelList());

		try {
			doModal();
		} catch (SuspendNotAllowedException e) {
			logger.fatal(&quot;&quot;, e);
			this.detach();
		} catch (InterruptedException e) {
			logger.fatal(&quot;&quot;, e);
			this.detach();
		}
	}

	/**
	 * Inner ListItemRenderer class.&lt;br&gt;
	 */
	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(&quot;data&quot;, data);
			ComponentsCtrl.applyForward(item, &quot;onDoubleClick=onDoubleClicked&quot;);
		}
	}

	/**
	 * If a DoubleClick appears on a listItem. &lt;br&gt;
	 * This method is forwarded in the renderer.&lt;br&gt;
	 *
	 * @param event
	 */
	public void onDoubleClicked(Event event) {

		if (listbox.getSelectedItem() != null) {
			Listitem li = listbox.getSelectedItem();
			Branche branche = (Branche) li.getAttribute(&quot;data&quot;);

			setBranche(branche);
			this.onClose();
		}
	}

	/**
	 * &quot;onPaging&quot; EventListener for the paging component. &lt;br&gt;
	 * &lt;br&gt;
	 * Calculates the next page by currentPage and pageSize values. &lt;br&gt;
	 * Calls the method for refreshing the data with the new rowStart and
	 * pageSize. &lt;br&gt;
	 */
	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(&quot;--&gt; : &quot; + start + &quot;/&quot; + getPageSize());
			}

			String searchText = _textbox.getValue();
			// refresh the list
			refreshModel(searchText, start);
		}
	}

	/**
	 * Refreshes the list by calling the DAO methode with the modified search
	 * object. &lt;br&gt;
	 *
	 * @param so
	 *            SearchObject, holds the entity and properties to search. &lt;br&gt;
	 * @param start
	 *            Row to start. &lt;br&gt;
	 */
	@SuppressWarnings(&quot;unchecked&quot;)
	void refreshModel(String searchText, int start) {

		// clear old data
		getListModelList().clear();

		// init the model
		ResultObject ro = getBrancheService().getAllBranchesLikeText(searchText, start, getPageSize());
		List&lt;Branche&gt; resultList = (List&lt;Branche&gt;) ro.getList();
		_paging.setTotalSize(ro.getTotalCount());

		// set the model
		setListModelList(new ListModelList(resultList));
		listbox.setModel(getListModelList());
	}

	/**
	 * Inner OnSearchListener class.&lt;br&gt;
	 */
	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.&lt;br&gt;
	 */
	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(&quot;data&quot;);

				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(&quot;brancheService&quot;);
		}
		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;
	}

}
</pre>
<p></code></p>
<p><span style="text-decoration: underline;"> The helper classfile:</span><br />
<code>
<pre class="brush: java;">
/**
 * A helper class that can hold a generic list and an int value. Used as the
 * totalSize value of possible records for paging components.&lt;br&gt;
 *
 * @author sgerth
 *
 */
public class ResultObject implements Serializable {

	private static final long serialVersionUID = 1L;

	// holds a generic List
	private List&lt;?&gt; list;

	// holds an int
	private int totalCount;

	public ResultObject() {
	}

	public ResultObject(List&lt;?&gt; list, int totalCount) {
		super();
		setList(list);
		setTotalCount(totalCount);
	}

	public List&lt;?&gt; getList() {
		return list;
	}

	public void setList(List&lt;?&gt; list) {
		this.list = list;
	}

	public int getTotalCount() {
		return totalCount;
	}

	public void setTotalCount(int totalCount) {
		this.totalCount = totalCount;
	}
}
</pre>
<p></code></p>
<p><span style="text-decoration: underline;"> The backend method uses Spring/Hibernate:</span><br />
<code>
<pre class="brush: java;">
	@SuppressWarnings(&quot;unchecked&quot;)
	@Override
	public ResultObject getAllBranchesLikeText(String text, int start, int pageSize) {
		DetachedCriteria criteria = DetachedCriteria.forClass(Branche.class);

		if (!StringUtils.isEmpty(text)) {
			criteria.add(Restrictions.ilike(&quot;braBezeichnung&quot;, text, MatchMode.ANYWHERE));
		}

		criteria.addOrder(Order.asc(&quot;braBezeichnung&quot;));

		int totalCount = getHibernateTemplate().findByCriteria(criteria).size();

		List&lt;Branche&gt; list = getHibernateTemplate().findByCriteria(criteria, start, pageSize);

		return new ResultObject(list, totalCount);
	}
</pre>
<p></code></p>
<p>Samples are hostet in the Zksample2 project on <img alt="" src="http://sourceforge.net/sflogo.php?group_id=297404" href="http://zksample2.sourceforge.net/" title="." class="alignnone" width="88" height="31" /></p>
<p>Have fun with it.</p>
<p>Stephan Gerth</p>
<p>Dipl.rer.pol.</p>
<hr />
PS: Help to prevent the global warming by writing cool software</p>
]]></content:encoded>
			<wfw:commentRss>http://www.forsthaus.de/blog/?feed=rss2&amp;p=360</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Modal search dialogs. Part 2: AdvancedSearchListBox skeleton.</title>
		<link>http://www.forsthaus.de/blog/?p=340</link>
		<comments>http://www.forsthaus.de/blog/?p=340#comments</comments>
		<pubDate>Thu, 01 Jul 2010 09:17:53 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[- ZK framework]]></category>

		<guid isPermaLink="false">http://www.forsthaus.de/blog/?p=340</guid>
		<description><![CDATA[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&#8217;ll discover that these [...]]]></description>
			<content:encoded><![CDATA[<p><strong>An advanced modal searchBox/selectionList with database paging which returns an object.</strong></p>
<p><a href="http://www.forsthaus.de/blog/?p=274">part 1</a> SimpleSearchListBox<br />
<a href="http://www.forsthaus.de/blog/?p=360">part 3</a> ExtendedSearchListBox</p>
<p>As we see in <a href="http://www.forsthaus.de/blog/?p=274">part 1</a> 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. </p>
<p>You&#8217;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. </p>
<p>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.</p>
<p><img title="AdvancedSearchListBox" src="http://www.forsthaus.de/zkoss/pics/advancedSearchListBox.jpg" alt="" width="380" height="300" /></p>
<p><span style="text-decoration: underline;"> calling in code:</span></p>
<p><code>
<pre class="brush: java;">
     Bean bean = AdvancedSearchListBox.show(parentComponent);

     if ( bean != null ) {
       // do something
       }
</pre>
<p></code></p>
<p><span style="text-decoration: underline;"> The classfile:</span><br />
<code>
<pre class="brush: java;">
/**
 * 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 &lt;http://www.gnu.org/licenses/gpl.html&gt;.
 */
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 &lt;br&gt;
 * can search and select a branch object. By onClosing this box &lt;b&gt;returns&lt;/b&gt;
 * an object or null. &lt;br&gt;
 * The object can returned by selecting and clicking the OK button or by
 * DoubleClicking on an item from the list.&lt;br&gt;
 *
 * &lt;br&gt;
 * This is a basic skeleton which is extended for database paging.&lt;br&gt;
 * &lt;br&gt;
 *
 * &lt;pre&gt;
 * call: Branch branch = BranchAdvancedSearchListBox.show(parentComponent);
 * &lt;/pre&gt;
 *
 * @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(&quot;message.Information.AdvancedSearch&quot;) + &quot; / &quot; + Labels.getLabel(&quot;common.Branch&quot;);

	// 1. Listheader
	private String _listHeader1 = Labels.getLabel(&quot;common.Description&quot;);

	// 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.&lt;br&gt;
	 *
	 * @param parent
	 */
	private BranchAdvancedSearchListBox(Component parent) {
		super();

		setParent(parent);

		createBox();
	}

	/**
	 * Creates the components, sets the model and show the window as modal.&lt;br&gt;
	 */
	@SuppressWarnings(&quot;unchecked&quot;)
	private void createBox() {

		// Window
		this.setWidth(String.valueOf(_width) + &quot;px&quot;);
		this.setHeight(String.valueOf(_height) + &quot;px&quot;);
		this.setTitle(_title);
		this.setVisible(true);
		this.setClosable(true);

		// Borderlayout
		Borderlayout bl = new Borderlayout();
		bl.setHeight(&quot;100%&quot;);
		bl.setWidth(&quot;100%&quot;);
		bl.setParent(this);

		Center center = new Center();
		center.setFlex(true);
		center.setParent(bl);

		South south = new South();
		south.setHeight(&quot;26px&quot;);
		south.setParent(bl);

		// Button
		Button btnOK = new Button();
		btnOK.setLabel(&quot;OK&quot;);
		btnOK.addEventListener(&quot;onClick&quot;, new OnCloseListener());
		btnOK.setParent(south);

		Div divCenter = new Div();
		divCenter.setWidth(&quot;100%&quot;);
		divCenter.setHeight(&quot;100%&quot;);
		divCenter.setParent(center);

		// Paging
		_paging = new Paging();
		_paging.addEventListener(&quot;onPaging&quot;, new OnPagingEventListener());
		_paging.setPageSize(getPageSize());
		_paging.setParent(divCenter);

		// Listbox
		listbox = new Listbox();
		listbox.setStyle(&quot;border: none;&quot;);
		listbox.setHeight(&quot;100%&quot;);
		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.&lt;br&gt;
		 * 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&lt;Branche&gt; resultList = (List&lt;Branche&gt;) ro.getList();
		_paging.setTotalSize(ro.getTotalCount());

		// set the model
		setListModelList(new ListModelList(resultList));
		listbox.setModel(getListModelList());

		try {
			doModal();
		} catch (SuspendNotAllowedException e) {
			logger.fatal(&quot;&quot;, e);
			this.detach();
		} catch (InterruptedException e) {
			logger.fatal(&quot;&quot;, e);
			this.detach();
		}
	}

	/**
	 * Inner ListItemRenderer class.&lt;br&gt;
	 */
	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(&quot;data&quot;, data);
			ComponentsCtrl.applyForward(item, &quot;onDoubleClick=onDoubleClicked&quot;);
		}
	}

	/**
	 * If a DoubleClick appears on a listItem. &lt;br&gt;
	 * This method is forwarded in the renderer.&lt;br&gt;
	 *
	 * @param event
	 */
	public void onDoubleClicked(Event event) {

		if (listbox.getSelectedItem() != null) {
			Listitem li = listbox.getSelectedItem();
			Branche branche = (Branche) li.getAttribute(&quot;data&quot;);

			setBranche(branche);
			this.onClose();
		}
	}

	/**
	 * &quot;onPaging&quot; EventListener for the paging component. &lt;br&gt;
	 * &lt;br&gt;
	 * Calculates the next page by currentPage and pageSize values. &lt;br&gt;
	 * Calls the method for refreshing the data with the new rowStart and
	 * pageSize. &lt;br&gt;
	 */
	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(&quot;--&gt; : &quot; + start + &quot;/&quot; + getPageSize());
			}

			// refresh the list
			refreshModel(start);
		}
	}

	/**
	 * Refreshes the list by calling the DAO methode with the modified search
	 * object. &lt;br&gt;
	 *
	 * @param so
	 *            SearchObject, holds the entity and properties to search. &lt;br&gt;
	 * @param start
	 *            Row to start. &lt;br&gt;
	 */
	@SuppressWarnings(&quot;unchecked&quot;)
	void refreshModel(int start) {

		// clear old data
		getListModelList().clear();

		// init the model
		ResultObject ro = getBrancheService().getAllBranches(start, getPageSize());
		List&lt;Branche&gt; resultList = (List&lt;Branche&gt;) ro.getList();
		_paging.setTotalSize(ro.getTotalCount());

		// set the model
		setListModelList(new ListModelList(resultList));
		listbox.setModel(getListModelList());
	}

	/**
	 * Inner OnCloseListener class.&lt;br&gt;
	 */
	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(&quot;data&quot;);

				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(&quot;brancheService&quot;);
		}
		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;
	}

}
</pre>
<p></code></p>
<p>For the backend helper class ResultObject() and the backend method please read part 3 of this article.</p>
<p>Samples are hostet in the Zksample2 project on <img alt="" src="http://sourceforge.net/sflogo.php?group_id=297404" href="http://zksample2.sourceforge.net/" title="." class="alignnone" width="88" height="31" /></p>
<p>Have fun with it.</p>
<p>Stephan Gerth</p>
<p>Dipl.rer.pol.</p>
<hr />
PS: Help to prevent the global warming by writing cool software</p>
]]></content:encoded>
			<wfw:commentRss>http://www.forsthaus.de/blog/?feed=rss2&amp;p=340</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Modal search dialogs. Part 1: SimpleSearchListBox skeleton.</title>
		<link>http://www.forsthaus.de/blog/?p=274</link>
		<comments>http://www.forsthaus.de/blog/?p=274#comments</comments>
		<pubDate>Tue, 29 Jun 2010 17:47:56 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[- ZK framework]]></category>

		<guid isPermaLink="false">http://www.forsthaus.de/blog/?p=274</guid>
		<description><![CDATA[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 [...]]]></description>
			<content:encoded><![CDATA[<p><strong>A modal searchBox/selectionList which returns an object.</strong></p>
<p><a href="http://www.forsthaus.de/blog/?p=340">part 2</a> AdvancedSearchListBox<br />
<a href="http://www.forsthaus.de/blog/?p=360">part 3</a> ExtendedSearchListBox</p>
<p>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 <a href="http://www.zkoss.org">zk framework</a> you can solve this by using a listbox with mold=&#8221;select&#8221; and rows=&#8221;1&#8243;. The outstanding feature  of such a component is that the &#8217;starter&#8217; 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.</p>
<p><strong>One </strong>possibility is to take a so called <strong>bandbox</strong> component and place all needed data limiting functionality with the listbox on it.</p>
<p><img title="SimpleSearchListBox" src="http://www.forsthaus.de/zkoss/pics/simpleSearchListBox.jpg" alt="" width="380" height="300" /><br />
The <strong>second </strong>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 <strong>get back an object</strong> of the needed bean from a window in a modal state.</p>
<p>For this requirement we let our SimpleSearchListBox class created by a private constructor that we called in a static way.</p>
<li></li>
<li></li>
<p><span style="text-decoration: underline;"> calling in code:</span></p>
<p><code>
<pre class="brush: java;">
     Bean bean = SimpleSearchListBox.show(parentComponent);

     if ( bean != null ) {
       // do something
       }
</pre>
<p></code></p>
<p><span style="text-decoration: underline;"> The classfile:</span><br />
<code>
<pre class="brush: java;">
/**
* 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 &lt;strong&gt;returns&lt;/strong&gt;
* 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(&quot;message.Information.Search&quot;) + &quot; &quot; + Labels.getLabel(&quot;common.Branch&quot;);
// 1. Listheader
private String _listHeader1 = Labels.getLabel(&quot;common.Description&quot;);
// 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) + &quot;px&quot;);
this.setHeight(String.valueOf(_height) + &quot;px&quot;);
this.setTitle(_title);
this.setVisible(true);
this.setClosable(true);

// Borderlayout
Borderlayout bl = new Borderlayout();
bl.setHeight(&quot;100%&quot;);
bl.setWidth(&quot;100%&quot;);
bl.setParent(this);

Center center = new Center();
center.setFlex(true);
center.setParent(bl);

South south = new South();
south.setHeight(&quot;26px&quot;);
south.setParent(bl);

// Button
Button btnOK = new Button();
btnOK.setLabel(&quot;OK&quot;);
btnOK.addEventListener(&quot;onClick&quot;, new OnCloseListener());
btnOK.setParent(south);

// Listbox
listbox = new Listbox();
listbox.setStyle(&quot;border: none;&quot;);
listbox.setHeight(&quot;100%&quot;);
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(&quot;&quot;, e);
this.detach();
} catch (InterruptedException e) {
logger.fatal(&quot;&quot;, 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(&quot;data&quot;, data);
ComponentsCtrl.applyForward(item, &quot;onDoubleClick=onDoubleClicked&quot;);
}
}

/**
* 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(&quot;data&quot;);

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(&quot;data&quot;);

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(&quot;brancheService&quot;);
}
return brancheService;
}

public void setBrancheService(BrancheService brancheService) {
this.brancheService = brancheService;
}
</pre>
<p></code></p>
<p>Samples are hostet in the Zksample2 project on <img alt="" src="http://sourceforge.net/sflogo.php?group_id=297404" href="http://zksample2.sourceforge.net/" title="." class="alignnone" width="88" height="31" /></p>
<p>Have fun with it.</p>
<p>Stephan Gerth</p>
<p>Dipl.rer.pol.</p>
<hr />
PS: Help to prevent the global warming by writing cool software</p>
]]></content:encoded>
			<wfw:commentRss>http://www.forsthaus.de/blog/?feed=rss2&amp;p=274</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
