Skip to content
mathieuancelin edited this page Feb 8, 2012 · 10 revisions

Create a new Portlet application using Chell

Set up the project

First you need to create a new Maven project that should look like that :

In your POM file you will need these dependencies :

<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>jstl</artifactId>
    <version>1.1.2</version>
</dependency>
<dependency>
    <groupId>taglibs</groupId>
    <artifactId>standard</artifactId>
    <version>1.1.2</version>
</dependency>
<dependency>
    <groupId>com.serli.chell.framework</groupId>
    <artifactId>chell-core</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>

Don't forget to set your packaging as 'war'. Then you're ready to go and you can start writing your first Chell controller.

Create the controller

The controller file takes place in the 'java/controller' package. For this sample, we create the HelloWorld.java controller. To enable it, you need to add the following lines to your portlets.xml(in the WEB-INF folder)

<portlet>
    <portlet-name>HelloWorld</portlet-name>
    <display-name>Hello World Portlet</display-name>
    <portlet-class>com.serli.chell.framework.ChellPortlet</portlet-class>
    <supports>
        <mime-type>text/html</mime-type>
        <portlet-mode>view</portlet-mode>
        <portlet-mode>edit</portlet-mode>
    </supports>
    <portlet-info>
        <title>Hello World Portlet</title>
    </portlet-info>
</portlet>

Be careful here, the 'portlet-name' attribute is important because it's used by the Chell Framework to find the right controller.

Then we can start writing our HelloWorld controller. Let's start with the Portlet render phase :

@OnRender(RenderMode.VIEW)
public void render() {
}

By default on render phase and in view mode, Chell framework will try to render a file named 'views/{ControllerName}/view.jsp'. Of course this behaviour is totally customizable, you just have to write

@OnRender(RenderMode.VIEW)
public String render() {
    return "MyOtherViewFile";
}

to use 'views/{ControllerName}/MyOtherViewFile.jsp'.

So, here we need to greet users with their name. To do so, we'll try to get a 'username' variable from the current model using dependency injection. If the 'username' variable isn't present in the model, we'll use a default value ("world").

@OnRender(RenderMode.VIEW)
public void render(Model model) {
    String username = model.forKey("username").getOrElse("World");
}

Now we can create our welcome message

@OnRender(RenderMode.VIEW)
public void render(Model model) {
    String welcomeMessage = "Hello " + model.forKey("username").getOrElse("World") + " !";
}

Now all we need to do is to say to the view : "Hey, I need you to render this 'welcomeMessage attribute'". So let's do it

@OnRender(RenderMode.VIEW)
public void render(Model model) {
    String welcomeMessage = "Hello " + model.forKey("username").getOrElse("World") + " !";
    Render.attr("welcomeMessage", welcomeMessage);
}

And we're good. Now we can write a minimal view.

Create the view

Open your view.jsp file and add the following lines

<%@ page pageEncoding="UTF-8" contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="portlet" uri="http://java.sun.com/portlet_2_0"%>
<%@ taglib prefix="chl" uri="http://serli.com/taglibs/chell"%>
<portlet:defineObjects />

<h1>${welcomeMessage}</h1>

The first lines are basic stuff for portlet usage. The interesting one is the following

<h1>${welcomeMessage}</h1>

In this part we say "Okay, when you will render a page, put the content of variable 'welcomeMessage' from model between these 'h1' tags".

Now our first portlet application is working.

Use Chell forms to get user name

Now, we need to allow the user to input its name so we can greet him. To do so, we'll use a very nice feature of Chell : the autogenerated html forms.

Let's open the UserNameForm.java (from model package) file and put these following lines

public class UsernameForm extends Form {

    @Required
    @HtmlInputText(label="Enter your name")
    private String username;

    public UsernameForm() {
        super("usernameform"); // the name of the form in the view
    }
    public String getUsername() { return username; }
    public void setUsername(String username) { this.username = username; }
}

Now with this file, we will be able to map a 'UsernameForm' POJO to an HTML form. So let's change our controller to take this new feature in account

@OnRender(RenderMode.VIEW)
public void render(Model model) {
    String welcomeMessage = "Hello " + model.forKey("username").getOrElse("World") + " !";
    Render.attr("welcomeMessage", welcomeMessage);
    Render.form(new UsernameForm());
}

And with the view

<%@ page pageEncoding="UTF-8" contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="portlet" uri="http://java.sun.com/portlet_2_0"%>
<%@ taglib prefix="chl" uri="http://serli.com/taglibs/chell"%>
<portlet:defineObjects />

<h1>${welcomeMessage}</h1>
<chl:form form="usernameform" action="submitUsername">
    <chl:errors />
    <chl:fields />
</chl:form>

Now that we can use Chell form in our portlet, we just need to link the form input to our controller logic. Let's add the following method to the HelloWorl controller

@OnAction("submitUsername")
public void submitUsername(UsernameForm form, Model model) {
    if (form.validate()) {
        model.attr("username", form.getUsername());
    }
}

Here we use dependency injection to get the current instance of the form from the request. And if the form is valid (meaning if the attribute username annotated with required isn't null) then, we add the 'username' variable in the model so the render phase will be able to use it.

And now, our application is working and says "Hello John Doe !" when John input his name.

Use portlet preferences

Now we can add a bit more of logic in our application and use portlet preference to do it. Let's add a new form for preferences, a new view for preferences and a new render method for EDIT mode.

@HtmlButtonCancel(action = CancelAction.DO_NOTHING)
public class PrefsForm extends Form {

    @HtmlInputCheckbox(label="Use uppercase")
    private String upper = ON;

    public PrefsForm() {
        super("prefform");
    }

    // getters and setters

in a file named 'edit.jsp' so the framework can bind it automatically to the EDIT phase.

<%@ page pageEncoding="UTF-8" contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="chl" uri="http://serli.com/taglibs/chell"%>

<chl:message-area />

<chl:form form="prefform" action="savePreferences">
    <chl:errors />
    <chl:fields />
</chl:form>

in HelloWorld.java

@OnRender(RenderMode.EDIT)
public void renderEdit(PrefsForm prefForm) {
    Render.form(prefForm);
}
    
@OnAction("savePreferences")
public void savePreferences(PrefsForm form) {
    if (form.validate()) {
        form.saveInPreferences();
    }
}

Now the only thing we have to do is to tweak our previous controller methods to take this new switch in account

@OnAction("submitUsername")
public void submitUsername(UsernameForm form, PrefsForm prefs, Model model) {
    if (form.validate()) {
        if (prefs.getUpper().equals(Form.ON)) {
            model.attr("username", form.getUsername().toUpperCase());
        } else {
            model.attr("username", form.getUsername());
        }
    }
}

Now our portlet applicatioin is fully working.

I hope you enjoyed this tutorial.