Wicket in Action

Working with background jobs

01 July 2014, by reiern70

The problem

From time to time Wicket users ask questions related to how to deal with background jobs in Wicket. E.g. “How do I make Application or Session available to a background thread?” Or, “How do I deal with showing some progress information, or allow the user to cancel a background process?”. We have build a small toy project to illustrate a possible way to do those things. We hope this project could help people get started on rolling their own solutions.

The complete code of the application can be found at: https://github.com/reiern70/antilia-bits/tree/master/bgprocess. Feel free to just grab the code and use it in any way you please.

The solution

We start by defining an interface that represents a Task. i.e. some lengthy computation to be done in a background non-WEB thread.

public interface ITask extends Serializable {

	void doIt(ExecutionBridge bridge);
}

the method doIt() receives a context/bridge class that can be used to communicate with the WEB layer.

public class ExecutionBridge implements Serializable {

	private String taskName;

	private volatile boolean stop = false;

	private volatile boolean cancel = false;

	private volatile int progress = 0;

	private String message;

	public ExecutionBridge() {
	}

	... setter and gettters
}

As an example we provide a dummy task, that looks like.

public class DummyTask implements ITask {

	private static final Logger LOGGER = LoggerFactory.getLogger(DummyTask.class);

	@javax.inject.Inject
	private IAnswerService answerService;
	
	public DummyTask() {
		Injector.get().inject(this);
	}
	
	@Override
	public void doIt(ExecutionBridge bridge) {

                // check thread locals are available
		LOGGER.info("App: {}", Application.exists());
		LOGGER.info("Session: {}", Session.exists());

		for(int i =1; i <= 100; ) {
			bridge.setProgress(i);
			if(bridge.isCancel()) {
				bridge.setMessage(answerService.getMessage(AnswerType.IS_CANCEL, i));
				// end the task!
				return;
			}
			if(bridge.isStop()) {
				bridge.setMessage(answerService.getMessage(AnswerType.IS_STOP, i));
			} else {
				bridge.setMessage(answerService.getMessage(AnswerType.ALL_OK, i));
				i++;
			}
			try {
				Thread.sleep(1000L);
			} catch (InterruptedException e) {
				bridge.setProgress(100);
				bridge.setMessage(answerService.getMessage(AnswerType.IS_ERROR, i));
				return;
			}
		}
	}
}

This task does nothing but iterate from 1 to 100 and repeatedly call a service, IAnswerService, to get some text messages to pass to the WEB layer via the ExecutionBridge instance. This class also uses information contained on bridge to determine if the task should be stopped or canceled. Mind that the task uses Wicket injection machinery to inject an implementation of IAnswerService, so, that mean we need to have Application as a thread local when Injector.get().inject(this); is called. This is achieved by providing a runnable that beside executing tasks, will make sure Application and Session are attached, and properly detached, as thread locals.

public class TasksRunnable implements Runnable {

	private final ITask task;
	private final ExecutionBridge bridge;
	private final Application application;
	private final Session session;

	public TasksRunnable(ITask task, ExecutionBridge bridge) {
		this.task = task;
		this.bridge = bridge;

		this.application = Application.get();
		this.session = Session.exists() ? Session.get() : null;
	}

	@Override
	public void run() {
		try {
			ThreadContext.setApplication(application);
			ThreadContext.setSession(session);
			task.doIt(bridge);
		} finally {
			ThreadContext.detach();
		}
	}
}

Additionally, we provide custom Session and Application classes containing the machinery to track user’s running tasks and to launch tasks, respectively. See

public class BgProcessApplication extends WebApplication {
	ExecutorService executorService =  new ThreadPoolExecutor(10, 10,
			0L, TimeUnit.MILLISECONDS,
			new LinkedBlockingQueue<Runnable>());

	@Override
	public Class<? extends WebPage> getHomePage() {
		return HomePage.class;
	}

	@Override
	public void init() {
		super.init();
		com.google.inject.Injector injector = Guice.createInjector(newModule());
		getComponentInstantiationListeners().add( new GuiceComponentInjector(this, injector));
	}

	@Override
	protected void onDestroy() {
		executorService.shutdown();
		try {
			if (!executorService.awaitTermination(2, TimeUnit.SECONDS)) {
				executorService.shutdownNow();
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		super.onDestroy();
	}

	private Module newModule() {
		return new Module() {
				public void configure(Binder binder) {
					binder.bind(IAnswerService.class).to(AnswerService.class);
				}
			};
	}

	public static BgProcessApplication get() {
		return (BgProcessApplication)get();
	}

	@Override
	public Session newSession(Request request, Response response) {
		return new BgProcessSession(request);
	}

	public void launch(ITask task) {
		// we are on WEB thread so services should be normally injected.
		ExecutionBridge bridge = new ExecutionBridge();
		// register bridge on session
		bridge.setTaskName("Task-" + BgProcessSession.getSession().countTasks() + 1);
		BgProcessSession.getSession().add(bridge);
		// run the task
		executorService.execute( new TasksRunnable(task, bridge));
	}
} 

and

public class BgProcessSession extends WebSession {

	private List<ExecutionBridge> bridges = new ArrayList<ExecutionBridge>();

	public BgProcessSession(Request request) {
		super(request);
	}

	public synchronized void add(ExecutionBridge bridge) {
		bind();
		bridges.add(bridge);
	}

	public synchronized void  pruneFinishedTasks() {
		ArrayList<ExecutionBridge> nonFinishedBridges = new ArrayList<ExecutionBridge>();
		for(ExecutionBridge bridge: this.bridges) {
			if (!bridge.isFinished()) {
				nonFinishedBridges.add(bridge);
			}
		}
		this.bridges = nonFinishedBridges;
	}

	public Iterator<ExecutionBridge> getTasksPage(int start, int size) {
		int min = Math.min(size, bridges.size());
		return new ArrayList<ExecutionBridge>(bridges.subList(start, min)).iterator();
	}

	public long countTasks() {
		return bridges.size();
	}

	public static BgProcessSession get() {
		return (BgProcessSession)get();
	}
}

The WEB layer to handle/manage tasks.

The WEB layer is more or less standard Wicket. The more complex class is TasksListPanel which uses an AjaxFallbackDefaultDataTable in order to display running tasks. This panel, contains an AjaxSelfUpdatingTimerBehavior that takes care of repainting the panel to show tasks progress. There are other user interactions, like creating new tasks and pruning “dead” tasks, but we will not get into the details.

public class TasksListPanel extends Panel {
	/**
	 * @param id
	 */
	public TasksListPanel(String id) {
		super(id);
		setOutputMarkupId(true);
		add( new AjaxLink<Void>("prune") {
			@Override
			public void onClick(AjaxRequestTarget target) {
				BgProcessSession.getSession().pruneFinishedTasks();
				target.add(TasksListPanel.this);
			}
		});
		add( new AjaxSelfUpdatingTimerBehavior( Duration.seconds(5) ) );
		ArrayList<IColumn<ExecutionBridge, String>> columns = new ArrayList<IColumn<ExecutionBridge,String>>();
		columns.add( new PropertyColumn<ExecutionBridge, String>(Model.of("Actions"), "-") { 
			@Override
			public void populateItem(
					Item<ICellPopulator<ExecutionBridge>> item,
					String componentId, IModel<ExecutionBridge> rowModel) {
				item.add( new ActionsPanel(componentId, rowModel) {
					@Override
					public void onAction(AjaxRequestTarget target) {
						TasksListPanel.this.add(new AjaxSelfUpdatingTimerBehavior( Duration.seconds(5)));
						target.add(TasksListPanel.this);
					}
				});
			}
		});
		columns.add( new PropertyColumn<ExecutionBridge, String>(Model.of("Name"), "taskName") );
		columns.add( new PropertyColumn<ExecutionBridge, String>(Model.of("Stoped"), "stop") );
		columns.add( new PropertyColumn<ExecutionBridge, String>(Model.of("Canceled"), "cancel") );
		columns.add( new PropertyColumn<ExecutionBridge, String>(Model.of("Message"), "message") );
		columns.add( new PropertyColumn<ExecutionBridge, String>(Model.of("Progress"), "progress") );
		columns.add( new PropertyColumn<ExecutionBridge, String>(Model.of("Finished"), "finished") );
		AjaxFallbackDefaultDataTable<ExecutionBridge, String> tasks = new AjaxFallbackDefaultDataTable<ExecutionBridge, String>("tasks", columns, new TaskDataProvider(), 10);
		add(tasks);
	}
	
	@Override
	public void onEvent(IEvent<?> event) {
		if(event.getPayload() instanceof TaskLaunchedEvent) {
			TaskLaunchedEvent event2 = (TaskLaunchedEvent)event.getPayload();
			TasksListPanel.this.add(new AjaxSelfUpdatingTimerBehavior( Duration.seconds(5)));
			event2.getTarget().add(TasksListPanel.this);
		}
	}
}

Final words

We hope this example helps you get started in rolling your own solution.

Last but not least, I would like to thanks Martin Grigorov for guiding me in writing this small article, making nice amendments to it and for he’s invaluable work maintaining Apache Wicket.

Build and watch resources with Gulp.js

01 July 2014, by martin-g

History

Lately I observe that the Node.js ecosystem provides much more (and better!) tools for building web applications. For example there are tools to generate CSS like Less.js, SASS, Stylus, minimizers like Clean CSS, Uglify JS, linting tools like JSHint and JSLint and many more. All these are available in the JVM world via Rhino but it is kind of slow… Maybe it will get better with Nashorn with Java 8 but it will take some time. And someone, like Wro4j, will have to create adapters for all these useful tools.

The solution

In my opinion it is much better to utilize the above tools directly with Node.js with its build tools like Gulp, Grunt, Gear, etc.

To accomplish that the most easier way I’ve found is by using frontend-maven-plugin

  • a Maven plugin that downloads Node.js for you and integrates with Gulp and Grunt.

Note: there is a Gradle plugin in the works by the same author!

Demo application

At my GitHub account you may find a demo application that uses Less to create the CSS resources and JSHint and UglifyJS to lint and minimize the JavaScript resources. At pom.xml we use frontend-maven-plugin to execute the default Gulp task that cleans and builds the final CSS and JS resources. The usage is as simple as mvn clean compile. At Maven’s generate-sources phase frontend-maven-plugin will execute the Gulp’s tasks.

Note: it will download Node.js and all needed Gulp plugins the first time and save them at ./node/ and ./node_modules/ folders. Make sure to ignore them in your SCM tool!

The usage in Wicket components is as you probably do it now:

  response.render(CssHeaderItem.forReference(new CssResourceReference(HomePage.class, "res/demo.css")));

In src/main/resources/com/mycompany/res folder there is demo.less resource but Gulp’s stylesInPackages task generates demo.css and puts it in the classpath, so everything Just Works™.

Bonus

Most of the Node.js build work flows provide a way to watch the resources for modifications and reload the browser automatically for you to see the changes. In the demo application we define watch task that listens for changes in the Less and JavaScript resources and executes the earlier tasks automatically. Additionally we make use of livereload-jvm at the server side that can notify browser plugins which will reload the page. To try it:

  1. execute *gulp watch* on the command line, in the same folder where gulpfile.js is located
  2. install the plugin for your preferred browser
  3. start the application via Start.java (starts embedded Jetty server and LiveReload-JVM server)
  4. open http://localhost:8080 in the browser
  5. open demo.less in your IDE and modify the background color to any valid color. Save the change.
  6. the browser will reload automatically !

Final words

I have played with all this on Linux. I’m pretty sure it will work flawlessly on Mac too. People say that Node.js support for Windows has become pretty good these days so it should work there too.

I hope you find all this useful!

Since recently Wicket itself uses the solution described above to execute its JavaScript unit tests.

In my daily job we switched from Node.js+less.js based build to Less4j because it is much faster and we have a lot of Less resources!

Groovy DSL for Apache Wicket

26 May 2014, by dashorst

Eugene Kamenev has released his take on making Wicket groovy:

Apache Wicket is great, and Groovy is also great. This project tries to combine the power of both. However, sometimes Apache Wicket code become damn verbose. But with some little, yet powerful Groovy DSL written, we can extend Wicket to simplify common tasks, and to delete over 30-40% of verbose code.

A short example of the usual Wicket and Java code:

...
Form form = new Form("wicketForm", new CompoundPropertyModel(this)) {
    @Override
    public void onSubmit(){
        System.out.println(MyPage.this.input1 + MyPage.this.input2);
    }
    @Override
    public boolean isVisible() {
        // just for example :)
        !MyPage.this.input1.equals(MyPage.this.input2);
    }
}
form.add(new TextField("input1"));
form.add(new TextField("input2"));
add(form);

These lines of code can be shortened by using Eugene’s Groovy DSL:

...
use(WicketDSL, WicketFormDSL) {
    def form('wicketForm', 
            new CompoundPropertyModel(this), 
            [
             submit:  { println this.input1 + this.input2 },
             visible: { this.input1 != this.input2 } 
            ]
        )
    form.field('input1')
    form.field('input2')
    this << form
}

You can see some example code in his readme file, and the project comes with some examples.

Go check it out!

Wicket in Action Makeover

30 March 2014, by dashorst

A couple of days ago the Wicket in Action website was unavailable without any notice. I’d like to explain why that was necessary and what I have done to prevent such outages in the future. This outage also presented an opportunity to work on the design of the Wicket in Action website.

Wicket in Action: hosted by Wordpress

Wicket in Action was powered by a self-hosted Wordpress installation since the beginning of this blog in 2008.

So why not use Wicket to create a blogging engine? I always figured that it was more important to write content, not the backend software. Hosting a Wordpress blog is almost gratis, where Java hosting brought considerable costs with it. The choice for Wordpress was quite simple at that time.

Wordpress has been a great blogging platform that got better with each release. Most notably the automatic updates were a boon and the admin UI was evolving nicely. With a press of a button I could upgrade my blogs to a new major release of Wordpress. And in the latest releases they even upgraded Wordpress for you automatically to patch releases.

Saying goodbye to Wordpress

Unfortunately Wordpress has been the target of malicious software, hackers and automated scripts. When you have to fully nuke and reinstall because a new exploit has crippled your site it is time part ways.

This caused quite a bit of a maintenance hassle, and a nagging feeling that at any given moment the website could be used to distribute malware or harvest information of blog visitors. A couple of months ago the website suddenly was blocked by google for distributing malware, causing visitors to see a big warning screen that the website could harm their computers.

The final straw that pushed me to turn off Wordpress was that I noticed in my access logs some weird pages that really had nothing to do with Wicket:

  • /2014/03/crack-sam-broadcaster-pro/
  • /2014/03/crack-wondershare-pdf-editor-or-serial-number/

These pages did not turn up in the Wordpress administration UI so it was difficult to spot them.

I immediately shutdown this website and my own personal blog. I have put a notice in place but somehow my hosting provider shows a ‘not registered’ page instead.

Goodbye Wordpress, I will not miss you.

Say hello to jekyll

The first thing I wanted to achieve was being free of active executing code on my hosting server. This led me to turning this website into serving only static markup.

Faster, more secure, better scalability

A static web site is safer than running Wordpress. There’s nothing to execute on the server! All the pages are pre-rendered and ready to be sent to browsers without any code executing. There are no accounts to break: all editing is done offline.

A static website is also much faster to serve by web servers. The web server only has to copy a file from disk to a network socket. There is no code execution inbetween: all pages are pre-rendered and nothing needs to be updated dynamically. This makes it easy to cache each page: in a file cache or in the HTTP server.

Having only static markup files makes it rather easy for a HTTP server to serve thousands of requests. Here’s a list Wordpress has to perform to serve a blog post:

  • start a PHP process
  • establish a connection to the database
  • query the database to retrieve the post
  • query the datebase to retrieve the author
  • query the database to retrieve the comments
  • query the database to retrieve active plugins
  • render the markup whilst executing any number of plugins and themes
  • close the connection to the database

I am sure I have missed quite a few steps in this list. While only a single step, there’s no saying what a given plugin and theme in Wordpress can do.

In the new, static content situation the HTTP server has the following tasks to perform:

  • read file from disk
  • send file to network

This is more concise and a lot easier to execute for a HTTP server.

One of the telltale indicators that a website is running a CMS (Wordpress) is when a highly trafficed site (for example Reddit, HackerNews, Slashdot, Daringfireball or Twitter) features the site on the front page, the server will crumble under the amount of incoming requests. Typically the first thing to give up is the database: with a couple of hundred concurrent requests it is bound to consume too much memory and the server will typically give up.

Wicket in action has not received that much traffic but you never know who will link to your blog post. Give a positive review of JEE 7 or Java 8 and suddenly you have thousands of Java developers looking at your post.

While not strictly necessary from a performance standpoint, moving to a static website makes sense.

Jekyll as the powering engine

There were a couple of factors to choose Jekyll as the platform for Wicket in Action and my other website:

  1. well known technology
  2. servable from github.com
  3. automatic migration from Wordpress

The Apache Wicket project uses Jekyll to generate the website. As such the Wicket committers have ample experience with Jekyll. The tooling is well understood and there’s ample documentation available.

Secondly github.com can serve Jekyll generated websites directly. You create a project and push your Jekyll content to github. A few moments later Github publishes the content. Github uses a CDN for the static websites. This gives our blog a global presence and speedy delivery.

I did not want to loose 6 years of content, so being able to import the Wordpress database and have all content available was a big plus.

I was able to replicate the URL schema of the Wordpress installation, so all links pointing to articles will still work (no broken web)!

A new design

At first the Wicket in Action website had a nice design that followed the book closely, but was tailored for a blog:

Screenshot of original Design of Wicket in Action

After a couple of Wordpress upgrades my custom theme did not work anymore. So I had to either reimplement my custom theme, or just pick a default theme. I chose the latter and Wicket in Action has used a plain design for some time. I was never happy with that.

The migration to Jekyll also brought a really hidious default design, so I had to do some design work.

The goals I set myself were:

  • stay close to the Wicket in Action book (use the smoking person, use the book color)
  • few menu items visible
  • clear, easy to read content
  • enough room for content and code examples

I wanted a content area that was wider than the original design to accomodate code better. I went into Keynote (my ‘design’ application) for the initial sketch and after letting it sit for a day started to implement it in the Jekyll site.

The result is what you see before you. It is not too snazzy, nor too fashionable.

A couple of things I have yet to address or implement:

  • author names instead of accounts
  • metadata clean up
  • code blocks design: better font and font-size
  • typography (font sizes of headings)
  • responsive UI (legibility on small devices)
  • search functionality
  • tags and categories (though who uses those anyway?)
  • reimplement comments
  • migrate all content from HTML to markdown

This new setup gives Wicket in Action (and my other blog) a good solid foundation for the coming years. I hope you like the new design and that new content keeps on flowing!

Header contributions positioning

14 March 2014, by martin-g

Wicket 6.0.0 came with some nice improvements in the header contribution management.

With these improvements it is possible to put a specific header contribution at the top of all others by using PriorityHeaderItem, or to group several header contributions in a specific spot in the page body by using FilteredHeaderItem, but still it was quite hard to something simple like making sure that <meta charset=”utf-8”/> is always the very first item in the page <head>.

<wicket:header-items/>

With WICKET-5531 (since Wicket 6.15.0) we added one more facility that should make header contributions management even more flexible.

By using markup like the one below in YourPage.html

<head>
  <meta chartset="UTF-8"/>
  <wicket:header-items/>
  <script src="my-monkey-patch-of-wicket-ajax.js"></script>
</head>

all header contributions done by using IHeaderResponse in your Java code or the special wicket:head tag will be put between the <meta> and <script> elements, i.e. in the place of <wicket:header-items/>.

This way you can make sure that some header item is always before or after the header items managed by Wicket.

<wicket:header-items/> can be used only in the page’s <head> element and there could be at most one instance of it.

Wicket at ApacheCon 2014: Croquet

09 March 2014, by dashorst

Due to an unfortunate scheduling conflict I'm unable to attend ApacheCon 2014 in North America, but
it appears that ApacheCon isn't bereft of a Wicket attendance: William Speirs is presenting his
Wicket, Jetty, Hibernate and Guice framework called "Croquet"
.

Croquet is a framework that combines Apache Wicket, Jetty, Hibernate, and Google’s Guice into a high-performance ops-friends web framework. Croquet is to Wicket as DropWizard is to Jersey.

When creating a website with Wicket, Jetty is often used for serving HTTP, Hibernate for interacting with databases, and Google’s Guice for dependency injection. Getting all of these components to run together properly is non-trivial and often repeated by each project. Croquet solves this problem by doing all of the hard work involved in tying these projects together, making it easier for developers to get a Wicket site up and running.

A brief introduction to each component, how the various pieces are tied together, and a walk through of creating a new Wicket site in Croquet will be covered in this presentation. Finally, the code for Croquet will be open sourced at the end of the presentation.

I'd love to be there...

The State of Wicket 2014

31 January 2014, by dashorst

In this short presentation I delivered at the first DEVdev meetup I talk about the ThoughtWorks Technology Radar January 2014 assessment of JSF, 10 years of Wicket history, the state of our community, the current releases and vision and roadmap for Wicket 6, 7 and 8.

The views, opinions and examples are all mine. What is presented here is not necessarily the opinion of the Wicket community, or the way we will do things in Wicket 7 or 8.

The State of Wicket from Martijn Dashorst

Enjoy this presentation!

Capture JavaScript errors and log them at the server

30 January 2014, by martin-g

ThoughtWorks technology radar recommends capturing client-side JavaScript errors and logging them at the server. This way you can see whether your application experience problems on different browsers.

A solution for Apache Wicket

Michael Haitz has implemented a small library that integrates with Wicket’s JavaScript APIs and captures and sends all client-side logs to the server.

Check its documentation to see how to setup and use it!

Surgical Ajax updates with Ractive.js

13 August 2013, by martin-g

Replace all with outerHTML

At the moment (Apache Wicket version 6.10.0) when a Component has to be updated in Ajax response Wicket will replace the whole HTML element with all its attributes and sub-elements included, i.e. the outerHTML of the element is replaced.

Wicket has always tried to do this in the most efficient way for the different browsers. Since version 6.0.0 Wicket uses jQuery to do this, so jQuery cares about the browser inconsistencies.

With or without using jQuery for DOM manipulations if the change in the DOM is as minimal as a new value for some attribute of the HTML element then Wicket will replace the whole element (including its sub-elements) to be able to update the attribute. Depending on the size of the markup this may be a noticeable or not.

Replace only what has changed with Ractive.js

In this article I want to introduce you Ractive.js - a JavaScript library that among other things is able to make surgical updates in the DOM tree.

Ractive.js uses templating based on Mustache. For example your markup template can look like:

<p id="myTmpl" style="color: ">Hello ! You have
    <strong> new messages</strong>.
</p>

To populate the data in the mustaches you need to initialize a Ractive instance with something like this:

var ractive = new Ractive({
  el: "#target",
  template: "myTmpl",
  data: {
    user: {
      color: "green",
      name: 'Dave',
      messages: { total: 11, unread: 4 }
    }
  }
});

This will read the template from the element with id “myTmpl” and put the final result in an element with id “target”.

Later if you need to update some variable (mustache) you should do:

ractive.set('user.messages.unread', 2);

This will update just the text node inside the strong HTML element responsible to visualize the number of the unread messages.

Even if we do something like:

ractive.set('user', {
  color: "green",
  name: "Dave",
  messages: {
    total: 11,
    unread: 2
  }
});

Note that only the unread has a new value, Ractive.js will figure that out and will do the right thing - will update the same text node only, as above, not the complete template.

The integration

At Wicket-Ractive you may find an integration between Wicket and Ractive that takes advantage of Ractive’s DOM update possibilities.

By adding RactiveBehavior to a component/panel Wicket will use its model object to create an instance of Ractive and populate its mustaches with initial values from the object’s properties. Later when updating this component you may use Ractive#ractive(AjaxRequestTarget, Component) helper to tell Ractive to do its magics and update only the bean properties which have new values.

Ractive#ractive(AjaxRequestTarget, Component) helper can be used when you know that the changes in the model object are small enough. In case there are bigger changes and replacing the outerHTML may be more efficient you can still use AjaxRequestTarget#add(Component) as you do now.

There is a demo application in the src/test/java folder of this project. Try it.

Conclusion

Ractive.js is used intensively at The Guardian but it is still a new project that has to prove itself among other good JavaScript libraries.

The usage of the mustaches in the markup template is against Wicket’s philosophy of developing with plain Java and plain HTML, so this approach may be a step in the wrong direction for some of the Wicket’s users.

Server and client side validation

24 April 2013, by martin-g

Maybe not so well known feature in Wicket is that the form component validators are actually Behaviors, or if they are not then a special adapter is used, so at the end they are stored as a behavior in the component.

Being a behavior gives the validator the chance to be notified when the respective form component is being rendered. And this makes it possible to make a validator that can validate at the server side and to contribute whatever is needed for some client side (JavaScript) library to make the same validation before the request is even made to the server.

At this repo you may find an integration with Parsley.js.

The implementation is in ParsleyValidationBehavior.
This is the base class that does most generic configuration, i.e. set the expected by Parsley data-xyz attributes in the form component markup. Additionally it uses a delegate IValidator that does the server side validation.

The usage is as any other validator in Wicket:

TextField<String> fullName = new TextField<String>("fullname", someModel);
fullName.add(new ParsleyValidationBehavior<String>(EmailValidator.getInstance()).type("email").require(true));

The code above is a bit mouthfull so we can create a specialization class:

public class ParsleyEmailValidator extends ParsleyValidationBehavior<String>
{
	public ParsleyEmailValidator()
	{
		super(EmailAddressValidator.getInstance());

		require(true);
		type("email");
	}
}

and use it like:

TextField<String> fullName = new TextField<String>("fullname", someModel);
fullName.add(new ParsleyEmailValidator());

The project just demostrates how to approach the problem. It does not provide full integration with Parsley.js.
If there is interest the project can be moved to WicketStuff and extended more with your help!

Update: Cedric Gatay extended the demo application with Bean Validation (JSR 303) support: Wicket + JSR_303 + Parsley. Good work, Cedric!

-->