ZKBoost addon: Realtime Admin Dashboard Module
A realtime admin dashboard sample that works with full-duplex connection to a WebSocket server. Runs inside the same Tomcat ZKBoost application.
( needs ZKBoost )
a blog about zk and wicket framework
A realtime admin dashboard sample that works with full-duplex connection to a WebSocket server. Runs inside the same Tomcat ZKBoost application.
( needs ZKBoost )
A chat module that works with full-duplex connection to a WebSocket server.
Runs inside the same Tomcat ZKBoost application.
( needs ZKBoost )
A guideline for creating homepages with ZK and Bootstrap. ( needs ZKBoost and Bootstrap 3.2 )
Creating an own Captcha component while it’s not in the zk community version.
As i work on the ‘forgotten password?’ module in openTruuls™ i would use a Captcha component for the user verification and i’m wondering that such a component is not in the zk community version. So openTruuls™ will be opensourced i need a Captcha component that developers can using without registering for a personal or commercial zk version.
After a few searching in the zk forum and the WWW i became a hint from Maik, the developer behind the jease cms ( www.jease.org ) to using the simpleCaptcha framework.
Argh, the biggest problem was to find a repository where a not corupted version is downloading via the maven2 build system. And let me talk that i’m do it at last by a manual downloading in the linux shell on our web server because i don’t find a runing version.
Okay, after done this, the result is a little Captcha Controller who creates the Captcha which we can call in a static way. In the forgottenPassword Controller we use this Captcha and get the image from it which we assign to a zk image.
pieces of the zul-template
. . . <!-- Captcha / Captcha --> <row> <space width="0" /> <hbox> <image id="img_Captcha" /> <toolbarbutton id="btnReCaptcha" image="/images/icons/sync_16x16.gif" tooltiptext="${c:l('common.ReCaptcha')}" /> </hbox> </row> . . .
The complete dialog should looks like in this picture:
- ForgottenPasswordController
the FDCaptchaUtils.java
/** * EN: Utility class for creating a CAPTCHA.<br> * Captcha can be direct loaded into a org.zkoss.zul.Image<br> * DE: Hilfsklasse zur Erzeugung eines CAPTCHA.<br> * Captcha kann direkt in ein org.zkoss.zul.Image eingelesen werden. * * <pre> * Image img = new org.zkoss.zul.Image(); * img.setContent(CaptchaUtils.getCaptcha().getImage()); * * String verifyStr = captcha.getAnswer(); * </pre> * * @author Stephan Gerth */ public class FDCaptchaUtils { public FDCaptchaUtils() { } /** * Create a 5 digits captcha. * * @return */ public static Captcha getCaptcha() { Captcha captcha = new Captcha.Builder(170, 50).addText(new ColoredEdgesWordRenderer()).addNoise().addBackground(new GradiatedBackgroundProducer()).addBorder().build(); return captcha; } }
In the forgotten password controller we create the Captcha and insert it in the zk Image and handles the verify logic.The needed methods in the controller code looks like this:
pieces of the ForgottenPassword controller
. . . private Captcha captcha; // + getter/setter . . . /** * Do a re-Captcha.<br> * * @param event */ private void doReCaptcha(Event event) { // init: disable the send password button btnReset.setDisabled(true); setCaptcha(FDCaptchaUtils.getCaptcha()); img_Captcha.setContent(getCaptcha().getImage()); } /** * 1. Checks if the email address is entered.<br> * 2. Verify the created captcha digits against the users input from a textbox.<br> * 3. Enable/disable the 'reset password' button.<br> * * @param event */ private void doVerifyCaptcha(Event event) { // init: disable the reset password button btnReset.setDisabled(true); // check if the tenant ID is entered if (StringUtils.isEmpty(longb_TenantID.getValue().toString().trim())) { throw new WrongValueException(longb_TenantID, Labels.getLabel("message.Error.CannotBeEmpty")); } // check if the email address is entered if (StringUtils.isEmpty(txtb_EmailAddress.getValue())) { throw new WrongValueException(txtb_EmailAddress, Labels.getLabel("message.Error.CannotBeEmpty")); } // check if the captcha is verified correctly if (StringUtils.equals(txtb_VerifyCaptcha.getValue(), getCaptcha().getAnswer())) { btnReset.setDisabled(false); } }
Have fun with it.Stephan Gerth
Dipl.rer.pol.
PS: Help to prevent the global warming by writing cool software
The opening of the sources of openTruuls™ ( powered ) will delayed a little bit because we will integrate jBPM5 (Business Process Management) Drools (Business Rules) and the Guvnor repository from jBoss.
In fact, we will prevent that there comes many needed code modifications/adaptions in future for special industries so we do early our best and take therefore the big step by integrating a professional BPM system where the developer can modify most of such things separate in a workflow. jBPM5 works BPMN 2.0 standard compliant.
In this case i will speak a welcome to Anton from Hannover(Germany) who joins the core developer team.
Interested people/partners write us under zk(at)forsthaus(dot)de
best
Stephan Gerth
At time we work hard on the codes for our new child called openTruuls™. It’s a business solution in the big field of the erp/crm software market. The multi-tenancy web-application is easy to extend for third party developers. It’s build to run in a clustered environment. For higher scaling the tenant/user/security database are separated from the tenants work data. So our goal is to offer this solution for smaller and middle sized firms as SaaS (Software as a Service) in a hosted environment. For using this system by in house servers in the customers firm we can offer the install, modify or extending of the solution and support them. openTruuls™ is an open source business application. It comes as a community edition or an enterprise edition with support. The application self is build on the MVC (model-view-controller) pattern on a stable stack of open source JAVA frameworks. For the frontend that runs in all common used browsers we select the great java AJAX web framework from Potix corp. the zk framework
. Spring, hibernate, hibernate-generic-dao are working in the middle layer. Out of the box the app will run against a PostgreSQL database. Running against mySQL, DB2, Informix, Sybase, SQL Server, Oracle or other Hibernate supported databases are doing by modifying the mapping files. For the reporting we use at time JasperReports with DynamicJasper. openTruuls™ have a full customizable rights management build on top of the spring security framework. Customers can define own access levels for their users and third party developers can easy extend their new written or modified modules with additional rights. In the case of financial accounting we have at first adopt a DATEV compatible accounting module for the german market with pre-defined charts of accounts for the SKR 03 and SKR 04.
Dashboard
System Manager
Interested people/partners write us under sge(at)oxitec(dot)de
best
Stephan Gerth
Dipl.rer.pol.
10. WebMonday in Magdeburg
On Monday i was speeking in Magdeburg on the WebMonday event about the zk framework.
It’s a nice event that take place every second monday in a month in many bigger cities worldwide. Here you can follow the speeches and meet some other guys who are interesting in Web Development.
This monday we have about 4 lectures and all speakers have only 15 minutes time for presenting their lecture and 15 minutes for questions and answers about their theme. I failed. It’s not possible to talk about zk in 15 minutes. I need 10 minutes more and i have luck. No one shoot me.
nice living room atmosphere
1. Suggy ( all guys from suggy )
2. InfoVis & OpenData ( Gregor Aisch )
3. Template Toolkit 2 ( Alexander Dahl )
4. ZK Ajax Web Framework ( Stephan Gerth )
For all visitors who wants to know more about the webMondays in Magdeburg follow these link.
A simple messageBarController that works with the new zk5 EventQueues mechanism.
In this article we will create a messaging system which is visually placed in the statusBar. We will call it messageBar and we add it as a Window component left before the statusBar window component as we explained in this previous post.
The ready implemented component are looks like this picture with only two icons in it. The red mail icon is for showing the message. This icon is blinking if there comes new messages in and the message reader is not opened (or if you uncomment a few lines in code it will popUp if a new message come in) . The right next icon is for opening a little window for writing a message text who can be send to all users.
Message Bar component
pieces of the zul-template
. . .
<!-- STATUS BAR AREA -->
<south id="south" border="none" height="22px"
splittable="false">
<div id="divSouth" align="left"
style="float: left; padding: 0px" width="100%">
<borderlayout width="100%" height="22px">
<west border="none" width="50px">
<!-- The MessageBar. Comps are created in the Controller -->
<window id="winMessageBar"
apply="${messageBarCtrl}" border="none" width="50px"
height="22px" />
</west>
<center border="none">
<!-- The StatusBar. Comps are created in the Controller -->
<window id="winStatusBar"
apply="${statusBarCtrl}" border="none" width="100%"
height="22px" />
</center>
</borderlayout>
</div>
</south>
. . .
The messageBar controller creates the two icons with their event Listeners and the global Listener for the messaging system. If you whish that an incoming message will popup self than you can uncomment the involved lines in the afterCompose method.
MessageBarCtrl.java
/**
* =======================================================================<br>
* MessageBarController. <br>
* =======================================================================<br>
* Works with the EventQueues mechanism of zk 5.x. ALl needed components are
* created in this class. In the zul-template declare only this controller with
* 'apply' to a winMessageBar window component.<br>
* This MessageBarController is for sending and receiving messages from other
* users.<br>
*
* The message text we do input with a special helper window that is called
* InputMessageTextBox.java
*
* <pre>
* < borderlayout >
* . . .
* < !-- STATUS BAR AREA -- >
* < south id="south" border="none" margins="1,0,0,0"
* height="20px" splittable="false" flex="true" >
* < div id="divSouth" >
*
* < !-- The MessageBar. Comps are created in the Controller -- >
* < window id="winMessageBar" apply="${messageBarCtrl}"
* border="none" width="100%" height="100%" />
* < !-- The StatusBar. Comps are created in the Controller -- >
* < window id="winStatusBar" apply="${statusBarCtrl}"
* border="none" width="100%" height="100%" />
* < /div >
* < /south >
* < /borderlayout >
* </pre>
*
* call for the message system:
*
* <pre>
* EventQueues.lookup("userNameEventQueue", EventQueues.APPLICATION, true).publish(new Event("onChangeSelectedObject", null, "new Value"));
* </pre>
*
*
* Spring bean declaration:
*
* <pre>
* < !-- MessageBarCtrl -->
* < bean id="messageBarCtrl" class="de.forsthaus.webui.util.MessageBarCtrl"
* scope="prototype">
* < /bean>
* </pre>
*
* since: zk 5.0.0
*
* @author sgerth
*
*/
public class MessageBarCtrl extends GenericForwardComposer implements Serializable {
private static final long serialVersionUID = 1L;
/*
* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
* All the components that are defined here and have a corresponding
* component with the same 'id' in the zul-file are getting autowired by our
* 'extends GFCBaseCtrl' GenericForwardComposer.
* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
*/
protected Window winMessageBar; // autowired
// Indicator column for message buttons
private Column statusBarMessageIndicator;
private Toolbarbutton btnOpenMsg;
private Toolbarbutton btnSendMsg;
private Window msgWindow = null;
private String msg = "";
private String userName;
/**
* Default constructor.
*/
public MessageBarCtrl() {
super();
}
@Override
public void doAfterCompose(Component window) throws Exception {
super.doAfterCompose(window);
try {
userName = ((UserImpl) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUsername();
} catch (Exception e) {
e.printStackTrace();
}
// Listener for incoming messages ( scope=APPLICATION )
EventQueues.lookup("testEventQueue", EventQueues.APPLICATION, true).subscribe(new EventListener() {
@Override
public void onEvent(Event event) throws Exception {
final String msg = (String) event.getData();
// Check if empty, than do not show incoming message
if (StringUtils.isEmpty(msg)) {
return;
}
setMsg(msg);
if (msgWindow == null) {
/**
* If you whish to popup the incoming message than uncomment
* these lines.
*/
// getMsgWindow();
// ((Textbox)
// getMsgWindow().getFellow("tb")).setValue(getMsg());
MessageBarCtrl.this.btnOpenMsg.setImage("/images/icons/incoming_message1_16x16.gif");
} else {
((Textbox) getMsgWindow().getFellow("tb")).setValue(getMsg());
}
}
});
}
/**
* Automatically called method from zk.
*
* @param event
*/
public void onCreate$winMessageBar(Event event) {
final Grid grid = new Grid();
grid.setHeight("100%");
grid.setWidth("50px");
grid.setParent(this.winMessageBar);
final Columns columns = new Columns();
columns.setSizable(false);
columns.setParent(grid);
// Column for the Message buttons
this.statusBarMessageIndicator = new Column();
this.statusBarMessageIndicator.setWidth("50px");
this.statusBarMessageIndicator.setStyle("background-color: #D6DCDE; padding: 0px");
this.statusBarMessageIndicator.setParent(columns);
Div div = new Div();
div.setStyle("padding: 1px;");
div.setParent(statusBarMessageIndicator);
// open message button
this.btnOpenMsg = new Toolbarbutton();
this.btnOpenMsg.setWidth("20px");
this.btnOpenMsg.setHeight("20px");
this.btnOpenMsg.setImage("/images/icons/message2_16x16.gif");
this.btnOpenMsg.setTooltiptext(Labels.getLabel("common.Message.Open"));
this.btnOpenMsg.setParent(div);
this.btnOpenMsg.addEventListener("onClick", new EventListener() {
@Override
public void onEvent(Event event) throws Exception {
// 1. Reset to normal image
btnOpenMsg.setImage("/images/icons/message2_16x16.gif");
// 2. open the message window
Window win = getMsgWindow();
Textbox t = (Textbox) win.getFellow("tb");
t.setText(getMsg());
// Clients.scrollIntoView(t);
}
});
// send message button
this.btnSendMsg = new Toolbarbutton();
this.btnSendMsg.setWidth("20px");
this.btnSendMsg.setHeight("20px");
this.btnSendMsg.setImage("/images/icons/message1_16x16.gif");
this.btnSendMsg.setTooltiptext(Labels.getLabel("common.Message.Send"));
this.btnSendMsg.setParent(div);
this.btnSendMsg.addEventListener("onClick", new EventListener() {
@Override
public void onEvent(Event event) throws Exception {
// open a box for inserting the message
Window win = (Window) Path.getComponent("/outerIndexWindow");
final String str = InputMessageTextBox.show(win);
EventQueues.lookup("testEventQueue", EventQueues.APPLICATION, true).publish(new Event("onTestEventQueue", null, str));
}
});
}
// +++++++++++++++++++++++++++++++++++++++++++++++++ //
// ++++++++++++++++ Setter/Getter ++++++++++++++++++ //
// +++++++++++++++++++++++++++++++++++++++++++++++++ //
public void setMsg(String msg) {
this.msg = this.msg + "\n" + msg;
}
public String getMsg() {
return msg;
}
public void setMsgWindow(Window msgWindow) {
this.msgWindow = msgWindow;
}
public Window getMsgWindow() {
if (msgWindow == null) {
msgWindow = new Window();
msgWindow.setId("msgWindow");
msgWindow.setTitle("Messages");
msgWindow.setSizable(true);
msgWindow.setClosable(true);
msgWindow.setWidth("400px");
msgWindow.setHeight("250px");
msgWindow.setParent(winMessageBar);
msgWindow.addEventListener("onClose", new EventListener() {
@Override
public void onEvent(Event event) throws Exception {
msgWindow.detach();
msgWindow = null;
}
});
msgWindow.setPosition("bottom, left");
Textbox tb = new Textbox();
tb.setId("tb");
tb.setMultiline(true);
tb.setRows(10);
tb.setReadonly(true);
tb.setHeight("100%");
tb.setWidth("98%");
tb.setParent(msgWindow);
msgWindow.doOverlapped();
}
return msgWindow;
}
}
If you click on the left mail icon a little window comes up and shows all messages that comes in since the user was logged in.
window for showing the messages
After clicking on the right icon there comes a window up for inserting the message text to send.
window for showing the messages
The code for the InputMessageTextBox looks like this:
InputMessageTextBox.java
/**
* This class creates a modal window as a dialog in which the user <br>
* can input some text. By onClosing with <RETURN> or Button <send> this
* InputConfirmBox can return the message as a String value if not empty. <br>
* In this case the returnValue is the same as the inputValue.<br>
*
* @author bbruhns
* @author sgerth
*/
public class InputMessageTextBox extends Window {
private static final long serialVersionUID = 8109634704496621100L;
private static final Logger logger = Logger.getLogger(InputMessageTextBox.class);
private final Textbox textbox;
private String msg = "";
private String userName;
/**
* The Call method.
*
* @param parent
* The parent component
* @param anQuestion
* The question that's to be confirmed.
* @return String from the input textbox.
*/
public static String show(Component parent) {
return new InputMessageTextBox(parent).getMsg();
}
/**
* private constructor. So it can only be created with the static show()
* method.
*
* @param parent
* @param anQuestion
*/
private InputMessageTextBox(Component parent) {
super();
textbox = new Textbox();
setParent(parent);
try {
userName = ((UserImpl) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUsername();
} catch (Exception e) {
e.printStackTrace();
}
createBox();
}
private void createBox() {
setWidth("350px");
setHeight("150px");
setTitle(Labels.getLabel("message.Information.PleaseInsertText"));
setId("confBox");
setVisible(true);
setClosable(true);
addEventListener("onOK", new OnCloseListener());
// Hbox hbox = new Hbox();
// hbox.setWidth("100%");
// hbox.setParent(this);
// Checkbox cb = new Checkbox();
// cb.setLabel(Labels.getLabel("common.All"));
// cb.setChecked(true);
Separator sp = new Separator();
sp.setParent(this);
textbox.setWidth("98%");
textbox.setHeight("80px");
textbox.setMultiline(true);
textbox.setRows(5);
textbox.setParent(this);
Separator sp2 = new Separator();
sp2.setBar(true);
sp2.setParent(this);
Button btnSend = new Button();
btnSend.setLabel(Labels.getLabel("common.Send"));
btnSend.setParent(this);
btnSend.addEventListener("onClick", new EventListener() {
@Override
public void onEvent(Event event) throws Exception {
// Check if empty, than do not send
if (StringUtils.isEmpty(StringUtils.trim(textbox.getText()))) {
onClose();
return;
}
msg = msg + ZksampleDateFormat.getDateTimeLongFormater().format(new Date()) + " / " + Labels.getLabel("common.Message.From") + " " + userName + ":" + "\n";
msg = msg + textbox.getText();
msg = msg + "\n" + "_____________________________________________________" + "\n";
onClose();
}
});
try {
doModal();
} catch (SuspendNotAllowedException e) {
logger.fatal("", e);
} catch (InterruptedException e) {
logger.fatal("", e);
}
}
final class OnCloseListener implements EventListener {
@Override
public void onEvent(Event event) throws Exception {
onClose();
}
}
// +++++++++++++++++++++++++++++++++++++++++++++++++ //
// ++++++++++++++++ Setter/Getter ++++++++++++++++++ //
// +++++++++++++++++++++++++++++++++++++++++++++++++ //
public void setMsg(String msg) {
this.msg = msg;
}
public String getMsg() {
return msg;
}
}
It’s now at your hands to implement the logic for sending a message to a selected user or user groups in the InputMessageTextBox and the logic for listening only to the user’s account who is the receiver of the message in the MessageBarCtrl.
Samples are hostet in the Zksample2 project on
Have fun with it.
Stephan Gerth
Dipl.rer.pol.
Coming soon…
Samples are hostet in the Zksample2 project on