Enterprise Java

Your first Juzu portlet on eXo platform

Juzu is a Buddhist prayer bead. One sentence and I am sure you have already learnt something, impressive no?

Ok, I won’t speak about Buddhism here.
Juzu is also a new framework for developing portlets (and standalone applications soon) very quickly. You can find all the information you need on the Juzu website.

Now let’s create our first portlet with Juzu !

Creating a new project

Juzu comes with a maven archetype. We can use it to quickly create our first application :

mvn archetype:generate \
   -DarchetypeGroupId=org.juzu \
   -DarchetypeArtifactId=juzu-archetype \
   -DarchetypeVersion=0.5.1 \
   -DgroupId=org.example \
   -DartifactId=myapp \
   -Dversion=1.0.0-SNAPSHOT

This creates a juzu project in a myapp folder.

Deploying the Juzu portlet

Before deploying the application, you need to build it.
Simply run mvn clean package in the myapp folder. It will generate a myapp.war under your myapp/target folder.

We are now ready to deploy the portlet in a portal container. We will use the latest GateIn release (3.4), the tomcat bundle version. Once downloaded, install it by unzipping it in the location of your choice.

The only thing you need to do is to drop the myapp.war file in the webapps folder, and start GateIn with bin/gatein.sh run.

Once started, add your portlet in a page. You should see :

Great ! You just finished your first Juzu portlet !

Let’s explore the project before enhancing it.

Exploring the project

The project structure looks like this :

The mandatory web.xml is there. It does not contain anything.

portlet.xml

The archetype generates a basic portlet.xml with some juzu init parameters :

<?xml version='1.0' encoding='UTF-8'?>
<portlet-app xmlns='http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd'
             version='2.0'
             xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
             xsi:schemaLocation='http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd
   http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd'>
   <portlet>
     <portlet-name>SampleApplication</portlet-name>
     <display-name xml:lang='EN'>Juzu Sample Application</display-name>
     <portlet-class>juzu.portlet.JuzuPortlet</portlet-class>
     <init-param>
       <name>juzu.run_mode</name>
       <value>prod</value>
     </init-param>
     <init-param>
       <name>juzu.inject</name>
       <value>weld</value>
       <!--
       <value>spring</value>
       -->
     </init-param>
     <supports>
       <mime-type>text/html</mime-type>
     </supports>
     <portlet-info>
       <title>Sample Application</title>
     </portlet-info>
   </portlet>
</portlet-app>

The portlet-class is the generic Juzu portlet class juzu.portlet.JuzuPortlet.
This class declares 2 init parameters :

  • juzu.run_mode
    • dev : changes made on source files are automatically hot recompiled and reloaded, so you don’t need to redeploy your application to test them. This is a real productivity boost while developing an application !
    • prod : “classic” mode, where you need to recompile and redeploy your application to apply your changes.
  • juzu.inject – defines the inject implementation. Two implementations are currently supported : weld (CDI Reference Implementation) and spring.

The Juzu portlet class uses the package-info.java file to gather needed extra information.

The portlet.xml file also contains basic information about the portlet : portlet-name, display-name and portlet-info. You can change them or add some others if needed.

package-info.java

This file contains all the configuration of the application.
The file allows to activate plugins, add JS/CSS resources, … but let’s keep it simple for now.
The only mandatory configuration is the declaration of the application, thanks to the @juzu.Application annotation. You have to declare the base package of your application, in our case org.sample.

Controller.java

This class is a Juzu controller. It is composed of a view method index (annotated with @View) which allows to render the index template.
The path of the index template is set with the @Path annotation. By default, Juzu uses the templates package of the application as its root path. So in our case, the template is located at org/sample/templates/index.gtmpl.

Switching to dev mode

Now that we know a little bit more about what is a Juzu application, let’s improve a little bit our basic helloworld application.
First of all, we will switch from prod to dev mode, in order to quickly test our changes. For that, edit your portlet.xml file and change the value of the init-param juzu.run_mode to dev. Then build your application and drop the war in the webapps folder of GateIn. Here you don’t need to stop/start GateIn as the webapp will be automatically redeployed.

As we did not change anything in the source files of our application, you should see the same “Hello World” message in your portlet.

In order to test the dev mode, you can for instance rename the file webapps/myapp/WEB-INF/src/org/sample/templates/index.gtmpl to index2.gtmpl. After refreshing your page, you will get the following message :

Now edit webapps/myapp/WEB-INF/src/org/sample/Controller.java and change

@Inject
@Path('index.gtmpl')
Template index;

by

@Inject
@Path('index2.gtmpl')
Template index;

and refresh your page once again.
Everything back to normal ! Pretty cool, isn’t it ?

Forms, Actions and type safe template parameters

We will create an application which displays the map of the location choosen by the user.
Firstly, update your index.gtmpl template :

#{param name=location/}
#{param name=mapURL/}

Location :
<form action='@{updateLocation()}' method='post'>
 <input type='text' name='location' value='${location}'/>
 <input type='submit'/>
</form>
<br/>
<%if(location) {%>
<div id='map'>
 
</div>
<%}%>
  • #{param name=location/} and #{param name=mapURL/} declares 2 type safe template parameters which will be used latter in our Controller
  • the form contains a input text, and submit to our juzu controller action updateLocation
  • finally, if a location is specified, the maps is displayed

Now, let’s update update our Controller.java :

package org.sample;

import juzu.Action;
import juzu.Path;
import juzu.Resource;
import juzu.Response;
import juzu.View;
import juzu.template.Template;

import javax.inject.Inject;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

public class Controller {

  @Inject
  @Path('index.gtmpl')
  org.sample.templates.index index;

  @View
  public void index() throws IOException {
    index('', '');
  }

  @View
  public void index(String location, String mapURL) throws IOException {
 index.with().location(location).mapURL(mapURL).render();
  }

  @Action
  public Response updateLocation(String location) throws IOException {
    String mapURL = 'https://maps.google.fr/maps?f=q&source=s_q&hl=en&geocode=&q=' + location + '&aq=&t=m&ie=UTF8&hq=&hnear=' + location + '&z=12&output=embed';

 return Controller_.index(location, mapURL);
  }
}
  • the index template is now of type org.sample.templates.index. This class is generated thanks to the annotations, and is a subclass of Template. Using this specific type will allow us to leverage declared template parameters, location and mapURL in our case.
  • the default index View now calls a new index View which accepts the location and mapURL arguments. This new view uses the index template class and its fluent syntax (do you like it ? Personnaly I do). Thanks to the declaration of the location and mapURL parameters in the template, the org.sample.templates.index template class accepts a location method and a mapURL method to set their values.
  • the updateLocation method is defined as an action thanks to tthe @Action annotation. It is called by the form to retrieve the correct URL (building the map URL is a basic example, generally you will call your services here). Then it redirects to the index View method in order to render the index template. Note the _ at the end of the Controller name. The class Controller_ is the “annotations processed” version of the Controller class.

If you did all these changes in the deployed version of your application (in webapps/myapp), you just need to refresh, and you should be able to enter a location and then see the corresponding map :



Ajax

Juzu provides some ease to use Ajax in your application. We will use them to avoid reloading our page when submitting a new location in our form.
The Ajax plugin needs JQuery. We can add it to our application by simply dropping the JQuery js file in the project and declare it in the package-info.java file with the Asset plugin (I dropped the JQuery js file in public/scripts) :

@juzu.plugin.asset.Assets(
 scripts = {
  @juzu.plugin.asset.Script(
   id = 'jquery',  
   src = 'public/scripts/jquery-1.7.1.min.js')
 }
)

We will now update our controller in order to add a new method which will only provide the map URL :

  @Ajax
  @Resource
  public Response.Content<Stream.Char> getMapURL(String location) throws IOException {
 String mapURL = 'https://maps.google.fr/maps?f=q&source=s_q&hl=en&geocode=&q=' + location + '&aq=&t=m&ie=UTF8&hq=&hnear=' + location + '&z=12&output=embed';

 return Response.ok('{\'mapURL\': \'' + mapURL +'\'}').withMimeType('application/json');
  }

Note that this new method is not annotated with @Action anymore. Annotating a method with @Ajax will make it accessible for Ajax calls. The @Resource annotation makes this method send the entire response to the client. That’s what we want as this method simply creates the new URL and sends it back to the client as a JSON response.

Finally, we have to update our template file to add the Ajax call :

#{param name=location/}
#{param name=mapURL/}

<script>
function submitLocation(location) {
 $('#map').jzAjax({
  url: 'Controller.getMapURL()',
  data: {'location': location}
 }).done(function(data) {
  $('#map > iframe').attr('src', data.mapURL);
 });
 return false;
}
</script>

Location :
<form onsubmit='return submitLocation(this.location.value)'>
 <input type='text' name='location' value='${location}'/>
 <input type='submit'/>
</form>
<br/>

<div id='map'>
 
</div>

The submission of the form now calls the submitLocation javascript function. This function uses the juzu Ajax function jzAjax (which uses the ajax JQuery function under the hood). This function calls the URL provided in the url param with the parameters provided in data. So here it will call the newly created method of our Controller and receive the new map URL in JSON :

{'mapURL': 'https://maps.google.fr/maps?f=q&source=s_q&hl=en&geocode=&q=nantes&aq=&t=m&ie=UTF8&hq=&hnear=nantes&z=12&output=embed'}

Then we just use JQuery to update the map.

Once again, simply refresh your page to see it in action !

You can now learn more on Juzu by going to the website or watching the screencasts.

Happy coding and don’t forget to share!

Reference: Your first Juzu portlet from our JCG partner Thomas Delhimenie at the T’s blog blog.

Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button