Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Ubercharts Live Charts with Wicket 6 and Websockets

DZone's Guide to

Ubercharts Live Charts with Wicket 6 and Websockets

· Big Data Zone
Free Resource

Effortlessly power IoT, predictive analytics, and machine learning applications with an elastic, resilient data infrastructure. Learn how with Mesosphere DC/OS.

Today we want you to show how you can provide live tracking charts for Web-based dashboards. This small showcase Application is based on Wicket 6Wicket Websockets and Ubercharts.

Just imagine you are running a high-frequency Webshop and you released new Features. And you want to see the feedback what have this features bring to you as soon as possible. Normally you have to wait up to 24h to get the the reports generated through your Business Intelligence Tools. To get reports immediately you have to provide dashboards which updates themselves automatically and which are available from everywhere. This requirements we solved with Wicket a Java Webframework for building Websites and UberchartsUbercharts is meant to be a tiny wrapper for apache wicket framework around the highcharts javascript library. The communication between the Wicket and Live Ubercharts will be provided by Wicket Websockets. In this post we show only the frontend part, not the backend part with saving tracking events.

Run the demo:

  1. Clone GitHub Repo: git clone git@github.com:comsysto/Ubercharts.git
  2. Go to the Ubercharts folder : cd Ubercharts
  3. git checkout wicketWebSockets
  4. gradle idea / gradle eclipse
  5. In IntelliJ IDEA or Eclipse open com.comsysto.runner.Start
  6. Start the main class
Uebercharts Bar Diagram

After running Ubercharts sample Application with websockets it’s should look like this

What should you see at the end :

Relevant Java Classes Diagram:

Live Charts Diagram

Java Class Diagram for Uberchart Websockets example application

The Webapplication starts with a DemoPage.java which only creates theDownloadChartModel.java and transfer it to the DownloadChartPanel.java class which handles the Websockets communication between server and the browser.

DownloadChartModel.java creates the charts with the Uberchart library, for initialize and show the chart is the initChart() method enough. As you can see we initialize the Series with emtyArray, because the data will bee update through Websockets in theDownloadChartPanel.java class.

private Highchart initChart() {
Number[] emptyArray = {};
ISeries<Number[]> rock = new NumberSeries(
MusikGenre.ROCK.getName()).setData(emptyArray);
ISeries<Number[]> urban = new NumberSeries(
MusikGenre.URBAN.getName()).setData(emptyArray).setVisible( false );
......
Highchart highchart = new Highchart( new BarChart(),
rock, pop, urban, electronic, bluesJazz);
return highchart;
}

For the Websocket communication we have to set events for the charts. The update events we add through highchart.getChart().getEvents().setLoad(getScript()); method the javascript fileDownloadsChartPanel.js. This javascript file subscribes for Websocket messages and updates the chart:

Wicket.Event.subscribe( "/websocket/open" , function (jqEvent) {
// show the initial state of the chart
});
Wicket.Event.subscribe( "/websocket/message" , function (jqEvent, message) {
// new record is pushed by the server
var record = jQuery.parseJSON(message);
if (record) {
if (record.type == '${messageType}' ){
columnChartUpdate(record.data, record.dataName);
}
if (record.type == '${messageSeriesType}' ){
columnChartCategoriesUpdate(record.data, record.dataName);
}
}
});

Websockets handling is initialized in the DownloadChartPanel.java inner classChartUpdatingBehavior. This inner class creates an UpdateTask.java which handles theWebSocketsConnectionRegistry and the connection handling in a separate thread:

@Override
public void run() {
IWebSocketConnectionRegistry webSocketConnectionRegistry =
new SimpleWebSocketConnectionRegistry();
while ( true ) {
Application application = Application.get(applicationName);
IWebSocketConnection connection = webSocketConnectionRegistry.
getConnection(application, sessionId, pageId);
if (connection == null || !connection.isOpen()) {
// stop if the web socket connection is closed
return ;
}
try {
updateFunction(connection);
// sleep for a while to simulate work
TimeUnit.SECONDS.sleep( 1 );
} catch (Exception x) {
x.printStackTrace();
return ;
}
}
}

In DownloadChartPanel we have to implement  UpdateTask abstract method updateFunction() in order to update update Chart with new data. UpdateTask sends every second a message with the new values for the chart in the updateFunction() method. The Data is here generated random in the method getDownloads(), there should be a DB or Service call instead for real data. This Websocket Message will bee handled from chart events javascript functions which are loaded in DownloadChartModel.java.

private class ChartUpdatingBehavior extends WebSocketBehavior {
@Override
protected void onConnect(ConnectedMessage message) {
super .onConnect(message);
// create an asynchronous task that will write the data to the client
UpdateTask updateTask = new UpdateTask(message.getApplication(),
message.getSessionId(), message.getPageId()) {
@Override
protected void updateFunction(IWebSocketConnection connection)
throws IOException {
ObjectMapper objectMapper = new ObjectMapper();
Message<Number[] > message = new Message<Number[]>(
MessageType.SERIES_UPDATE,selectedGenreType.name(), getDownloads());
String json = objectMapper.writeValueAsString(message);
connection.sendMessage(json);
}
};
Executors.newScheduledThreadPool( 1 ).schedule(updateTask, 1 , TimeUnit.SECONDS);
}

So now we have one way communication from the Server to the Client. Now we want to change the Music genre in the webfronted with a click on the Chart Legend. For that we add in the ChartModel the ChartCategorySwitch.js which is called on chart click function. The Script sends Wicket.Websocket message to the Server with the name of the selected genre.

function productSwitchUpdate (event) {
var selected = this .index;
var allSeries = this .chart.series;
$.each(allSeries, function (index, series) {
if (selected == index ){
series.show() ;
var message= '{"type":"' + '${messageType}' + '","dataName":"' +series.name+ '"}'
Wicket.WebSocket.send(message);
} else {
series.hide();
}
});
return false ;
}

The Server hadles the click-message in the DownloadsChartPanel.java getWebSocketBehaviorForClicks() method. This method Listens for Websockets Messages and when a GENRE_UPDATE Message comes in selectedGenreType will be set. When a Websocket message will be pushed back to the chart with the new categories names.

private Behavior getWebSocketBehaviorForClicks() {
return new WebSocketBehavior() {
@Override
protected void onMessage(WebSocketRequestHandler handler,TextMessage message){
try {
ObjectMapper objectMapper = new ObjectMapper();
Message parsedMsg = objectMapper.readValue(message.getText(),
new TypeReference() {});
if (parsedMsg.getType() == MessageType.GENRE_UPDATE){
selectedGenreType = MusikGenre.valueOf(
parsedMsg.getDataName().toUpperCase());
Message<String[]> msg = new Message<String[]>(
MessageType.CATEGORIES_UPDATE,selectedGenreType.name(),
musikGenreMap.get(selectedGenreType));
String json = objectMapper.writeValueAsString(msg);
handler.push(json);
}
} catch (IOException e) {
e.printStackTrace();
}
}
};
}

While developing  we have some problems to get it running in Jetty and Tomcat with the same war file. For fixing it you have to add dependencies in the build.gradle file:

"org.apache.wicket:wicket-native-websocket-jetty:0.6" ,
"org.apache.wicket:wicket-native-websocket-tomcat:0.6" ,

and also add a filter in web.xml file:

//ENABLE WHEN JETTY
< filter-class >org.apache.wicket.protocol.ws.jetty.Jetty7WebSocketFilter</ filter-class >
//ENABLE WHEN TOMCAT
< filter-class >org.apache.wicket.protocol.ws.tomcat7.Tomcat7WebSocketFilter</ filter-class >

Next steps are migrating it to jetty 9 and add some Wrapper for Ubercharts to easier add Updating tasks.

Learn to design and build better data-rich applications with this free eBook from O’Reilly. Brought to you by Mesosphere DC/OS.

Topics:

Published at DZone with permission of Comsysto Gmbh, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}