Our Blog

Let us find tech solutions together

Feb 10

We’ve been seeing more and more implementations of IPageStore out in the wild for Apache Wicket. The interface basically decides how Wicket will store the Pagemap for your application. The default that ships with Wicket uses DiskPageStore which is an implementation that stores the serialized pages grouped in a single file per pagemap. After reading a wonderful blog post on Letsgetdugg a few days ago: Clustering Wicket for fun and profit!, I decided to take a look at writing an implementation using Hazelcast - an “open source clustering and highly scalable data distribution platform”. The implementation below borrows heavily from Victor. It basically creates a HazelcastInstance in the constructor and then overrides all the methods necessary from AbstractPageStore. Here’s some quick code to put in your app’s Application implementation that will use this new IPageStore:

1
2
3
4
5
    @Override
    protected ISessionStore newSessionStore() {
        return new SecondLevelCacheSessionStore(this,
                new HazelcastPageStore("default"));
    }

And here’s the code for HazelcastPageStore:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
public class HazelcastPageStore extends AbstractPageStore
                                      implements SecondLevelCacheSessionStore.IClusteredPageStore {

    private Logger logger = LoggerFactory.getLogger(HazelcastPageStore.class);

    private String mapName;
    private HazelcastInstance client;

    public HazelcastPageStore(String mapName) { this(mapName, null); }

    public HazelcastPageStore(String mapName, Config config) {
        this.mapName = mapName;
        client = Hazelcast.newHazelcastInstance(config);
    }

    public String getKey(final String sessId, final String pageMapName, final int pageId, final int pageVersion) {
        return getKey(sessId, pageMapName, pageId, pageVersion, -1);
    }

    public String getKey(final String sessId, final String pageMapName, final int pageId, final int pageVersion, final int ajaxVersion) {
        String key = sessId + ":" + pageMapName + ":" + pageId + ":" + pageVersion + ":" + ajaxVersion;
        if (logger.isDebugEnabled()) {
            logger.debug("GetKey: " + key);
        }
        return key;
    }

    public String storeKey(final String sessionId, final Page page) {
        String key = sessionId + ":" + page.getPageMapName() + ":" + page.getId() + ":" + page.getCurrentVersionNumber() + ":" + (page.getAjaxVersionNumber() - 1);
        if (logger.isDebugEnabled()) {
            logger.debug("StoreKey: " + key);
        }
        return key;
    }

    public boolean containsPage(final String sessionId, final String pageMapName, final int pageId, final int pageVersion) {
        return client.getMap(mapName).containsKey(getKey(sessionId, pageMapName, pageId, pageVersion));
    }

    public void destroy() {
        client.shutdown();
    }

    public <t> Page getPage(final String sessionId, final String pagemap, final int id, final int versionNumber, final int ajaxVersionNumber) {
        IMap<string, Page> map = client.getMap(mapName);

        return map.get(getKey(sessionId, pagemap, id, versionNumber, ajaxVersionNumber));
    }

    public void pageAccessed(final String sessionId, final Page page) {
    }

    public void removePage(final String sessionId, final String pagemap, final int id) {
        String key = getKey(sessionId, pagemap, id, 0);
        key = key.substring(0, key.lastIndexOf(":"));

        IMap<string, Page> map = Hazelcast.getMap(mapName);
        for (String k : map.keySet()) {
            if (k.startsWith(key)) {
                map.remove(k);
            }
        }
    }

    public void storePage(final String sessionId, final Page page) {
        IMap<string, Page> map = client.getMap(mapName);
        map.put(storeKey(sessionId, page), page);
    }

    public void unbind(final String sessionId) {
        IMap<string, Page> map = client.getMap(mapName);
        for (String key : map.keySet()) {
            if (key.startsWith(sessionId)) {
                map.remove(key);
            }
        }
    }
}

Several other IPageStore implementations available:

Let us know if you find any others out in the wild so we can add them here.

Read more
Feb 10

(Editor’s note: Tomasz Dziurko contributed this column from Code Hard Go Pro.)

While developing web application with Wicket I sometimes need to check whether the user really, really does want to do something, for example to delete an entity from the database. The first and easiest choice that comes to my mind is to use JavaScript window. So we have HomePage.html:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!DOCTYPE html
    PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd" >
    <head>
        <title>Wicket Ajax 'Are you sure?' Modal Window</title>
    </head>
    <body>
        <div align="center">
            <strong>Wicket Ajax 'Are you sure?' Modal Window</strong>
            <form action="" wicket:id="formWithJavaScript">
                <input type="submit" wicket:id="buttonWithJavaScript" value="Action!"/>
            </form>
        </div>
    </body>
</html>

and corresponding Java class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package pl.tdziurko.ajaxmodalwindowapp;

// imports omitted

/**
 * Author: Tomasz Dziurko
 */

public class HomePage extends WebPage {

    private static final long serialVersionUID = 1L;

    public HomePage(final PageParameters parameters) {

        Form formWithJavaScript = new Form("formWithJavaScript");

        Button buttonWithJavaScript = new Button("buttonWithJavaScript") {

            @Override
            public void onSubmit() {
                System.out.println("Doing my job");
            }
        };
        buttonWithJavaScript.add(new SimpleAttributeModifier(
                "onclick", "if(!confirm('Do you really want to perform this action?')) return false;"));

        formWithJavaScript.add(buttonWithJavaScript);
        add(formWithJavaScript);

    }

}

Finally, we can see how it looks:

It solves our problem but in the era of Web2.0, rounded corners and shiny looks it isn’t enough. Why can’t we use ajax modal window to ask user for confirmation? It would make our application look good and our css magician could make it look even better.

So let’s try with creating reusable ‘Are you sure?’ ajax modal window with Wicket.

At the beginning we must prepare panel which will be displayed in our modal window. Let’s name it YesNoPanel.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html
    PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns:wicket>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
        <title></title>
    </head>
    <body>
        <wicket:panel>
            <form wicket:id="yesNoForm" action="">
                <span wicket:id="message">Are you sure?</span>
                <table style="width: 65%;" align="center">
                    <tr>
                        <td align="left">
                            <input type="submit" wicket:id="noButton" value="No" />
                        </td>
                        <td align="right">
                            <input type="submit" wicket:id="yesButton" value="Yes" />
                        </td>
                    </tr>
                </table>
            </form>
        </wicket:panel>
    </body>
</html>

and Java class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
package pl.tdziurko.ajaxmodalwindowapp.areyousuremodal;

import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.markup.html.form.AjaxButton;
import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
import org.apache.wicket.markup.html.basic.MultiLineLabel;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.panel.Panel;
import pl.tdziurko.ajaxmodalwindowapp.areyousuremodal.AreYouSurePanel.ConfirmationAnswer;

public class YesNoPanel extends Panel {

    public YesNoPanel(String id, String message, final ModalWindow modalWindow, final ConfirmationAnswer answer) {
        super(id);

        Form yesNoForm = new Form("yesNoForm");

        MultiLineLabel messageLabel = new MultiLineLabel("message", message);
        yesNoForm.add(messageLabel);
        modalWindow.setTitle("Please confirm");
        modalWindow.setInitialHeight(200);
        modalWindow.setInitialWidth(350);

        AjaxButton yesButton = new AjaxButton("yesButton", yesNoForm) {

            @Override
            protected void onSubmit(AjaxRequestTarget target, Form form) {
                if (target != null) {
                    answer.setAnswer(true);
                    modalWindow.close(target);
                }
            }
        };

        AjaxButton noButton = new AjaxButton("noButton", yesNoForm) {

            @Override
            protected void onSubmit(AjaxRequestTarget target, Form form) {
                if (target != null) {
                    answer.setAnswer(false);
                    modalWindow.close(target);
                }
            }
        };

        yesNoForm.add(yesButton);
        yesNoForm.add(noButton);

        add(yesNoForm);
    }

}

Everything looks pretty straightforward. We pass to the constructor text which will be displayed as a confirmation question, references to ModalWindow object in which YesNoPanel is placed and to ConfirmationAnswer object. ConfirmationAnswer class will be created in the next paragraph and will be used to store information whether user pressed ‘Yes’ or ‘No’ button in our panel.

Now it’s time to prepare wrapping form to our YesNoPanel. We could simply achieve it by creating panel with form and one button in it. In our example it will be AreYouSurePanel class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html
    PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns:wicket>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
        <title></title>
    </head>
    <body>
        <wicket:panel >
            <form wicket:id="confirmForm" action="" style="display: inline;">
                <input type="submit" wicket:id="confirmButton" value="Default name" />
                <span style="display: none;" wicket:id="modal"></span>
            </form>
        </wicket:panel>
    </body>
</html>

and in Java:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
package pl.tdziurko.ajaxmodalwindowapp.areyousuremodal;

import java.io.Serializable;
import java.util.Map;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.markup.html.form.AjaxButton;
import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.Model;


public abstract class AreYouSurePanel extends Panel {

    protected ModalWindow confirmModal;
    protected ConfirmationAnswer answer;
    protected Map<string,string> modifiersToApply;


    public AreYouSurePanel(String id, String buttonName, String modalMessageText) {
        super(id);
        answer = new ConfirmationAnswer(false);
        addElements(id, buttonName, modalMessageText);
    }

    protected void addElements(String id, String buttonName, String modalMessageText) {

        confirmModal = createConfirmModal(id, modalMessageText);

        Form form = new Form("confirmForm");
        add(form);

        AjaxButton confirmButton = new AjaxButton("confirmButton", new Model(buttonName)) {

            @Override
            protected void onSubmit(AjaxRequestTarget target, Form form) {
                confirmModal.show(target);
            }
        };

        form.add(confirmButton);


        form.add(confirmModal);

    }

    protected abstract void onConfirm(AjaxRequestTarget target);
    protected abstract void onCancel(AjaxRequestTarget target);

    protected ModalWindow createConfirmModal(String id, String modalMessageText) {

        ModalWindow modalWindow = new ModalWindow("modal");
        modalWindow.setCookieName(id);
        modalWindow.setContent(new YesNoPanel(modalWindow.getContentId(), modalMessageText, modalWindow, answer));
        modalWindow.setWindowClosedCallback(new ModalWindow.WindowClosedCallback() {

            @Override
            public void onClose(AjaxRequestTarget target) {
                if (answer.isAnswer()) {
                    onConfirm(target);
                } else {
                    onCancel(target);
                }
            }
        });

        return modalWindow;
    }

    public class ConfirmationAnswer implements Serializable {

        private boolean answer;

        public ConfirmationAnswer(boolean answer) {
            this.answer = answer;
        }

        public boolean isAnswer() {
            return answer;
        }

        public void setAnswer(boolean answer) {
            this.answer = answer;
        }
    }

}

Here we do following steps:

  1. Create form with one AjaxButton which shows modalWindow when clicked.
  2. Create modalWindow with YesNoPanel in it. As mentioned earlier, we pass there references to our modal window and to confirmationAnswer object.
  3. Add WindowClosedCallback to modalWindow and basing on user choice perform onConfirm or onCancel method. These methods are both abstract to force developer extending AreYouSurePanel to implement them according to his needs.

That’s it, we are done. To test how it’s working we must change a bit our page class and html file:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<!DOCTYPE html
    PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd" >
    <head>
        <title>Wicket Ajax 'Are you sure?' Modal Window</title>
    </head>
    <body>




        <div align="center">
            <strong>Wicket Ajax 'Are you sure?' Modal Window</strong>




            <form action="" wicket:id="formWithJavaScript">
                <input type="submit" wicket:id="buttonWithJavaScript" value="Action!"/>
            </form>
        </div>



        <div align="center">
            <span wicket:id="yesNoPanel"/>
        </div>

    </body>
</html>

and

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package pl.tdziurko.ajaxmodalwindowapp;

// imports omitted

public class HomePage extends WebPage {

    private static final long serialVersionUID = 1L;

    public HomePage(final PageParameters parameters) {

        Form formWithJavaScript = new Form("formWithJavaScript");

        Button buttonWithJavaScript = new Button("buttonWithJavaScript") {

            @Override
            public void onSubmit() {
                System.out.println("Doing my job");
            }
        };
        buttonWithJavaScript.add(new SimpleAttributeModifier(
                "onclick", "if(!confirm('Do you really want to perform this action?')) return false;"));

        formWithJavaScript.add(buttonWithJavaScript);
        add(formWithJavaScript);

        AreYouSurePanel yesNoPanel = new AreYouSurePanel("yesNoPanel", "Ajax Action!", "Do you really want to perform this action?") {

            @Override
            protected void onConfirm(AjaxRequestTarget target) {
                System.out.println("Doing my job after ajax modal");
            }

            @Override
            protected void onCancel(AjaxRequestTarget target) { }

        };

        add(yesNoPanel);
    }

}

And after clicking ‘Ajax Action!’ we could see that it’s working as intended:

Read more
Feb 09

Last week I was searching examples while working in integrating OpenID in a Java Web Applications and I found a very recent article (January 27th) on the IBM developerWorks.

OpenID for Java Web applications, Part 1 by J Steven Perry offer a panoramic about OpenID in a modern web applications and uses Apache Wicket as Web framework for the example. The article is really good and offers the whole source code as download.

This article talk about implementing an OpenID consumer Service while the part two will focus on writing an OpenID provider.

Read more