JBoss.orgCommunity Documentation

Chapter 6. Portlet development

6.1. Web User Interface - WebUI
6.1.1. Relevant Sections
6.2. AJAX Framework
6.2.1. Portlet Preparation
6.2.2. AJAX in Groovy
6.2.3. How JavaScript works
6.2.4. PortletResponse
6.2.5. PortalResponse
6.2.6. AjaxRequest
6.2.7. HttpResponseHandler
6.2.8. Manage Several Popups
6.3. Groovy Templates
6.3.1. Basic structure
6.3.2. Groovy language
6.3.3. Linking a portlet with a template
6.4. Portlet Lifecycle
6.4.1. Portlet init
6.4.2. Portlet request handler
6.4.3. ProcessAction phase
6.4.4. Render phase
6.5. Portlet Primer
6.5.1. JSR-168 and JSR-286 overview
6.5.2. Tutorials
6.6. Create a WebUI Portlet
6.6.1. Overview
6.6.2. Configure the portlet
6.6.3. Use the Portlet
6.6.4. Add a "HelloWorld" popup

WebUI is the name of 's webframework.

Using a self-contained framework ensures that the portal's architecture does not interfere with other web technologies deployed by the portlets.

Using a particular technology raises potential difficulties for users with a differing version (either newer or older) of the same technology.

The WebUI framework is a component tree based framework. The key aspects of WebUI are :

Ajax calls are easily managed in 's framework. Lines can be added to the relevant template file and java class. A simple Ajax update of a component does not require any JavaScript code to be written.

portlets can use specific ActionListeners to receive and process Ajax calls. To set a portlet up to recieve Ajax calls, follow this procedure:

  1. Create an inner static class named with the following convention: action name followed by ActionListener.

    Example : ParentClass is the class being wrtitten in.

    static public class SaveActionListener extends EventListener<ParentClass>
    
  2. Declare this listener in the configuration of the portlet:

    listeners = ParentClass.SaveActionListener.class
    
  3. Add the correct annotation ComponentConfig, EventConfig, etc.

    For example; the configuration below is for UIAccountForm:

    ...
    
    @ComponentConfig(
      lifecycle = UIFormLifecycle.class,
      template =  "system:/groovy/webui/form/UIFormTabPane.gtmpl",
      initParams = {   
        @ParamConfig(
          name = "AccountTemplateConfigOption", 
          value = "app:/WEB-INF/conf/uiconf/account/webui/component/model/AccountTemplateConfigOption.groovy"
        ),
        @ParamConfig(
          name = "help.UIAccountFormQuickHelp",
          value = "app:/WEB-INF/conf/uiconf/account/webui/component/model/UIAccountFormQuickHelp.xhtml"
        )
      },
      events = {
        @EventConfig(listeners = UIAccountForm.SaveActionListener.class ),
        @EventConfig(listeners = UIAccountForm.ResetActionListener.class, phase = Phase.DECODE),
        @EventConfig(listeners = UIAccountForm.SearchUserActionListener.class, phase = Phase.DECODE)
      }
    )
    ...
  4. Create an execute method inside this class:

    public void execute(Event<ParentClass> event) throws Exception
    

    This method is called every time the listener gets an event from the client. Hence you can process this event in it, using the even attribute. Use it to get parameters from a form in your client, to modify the status of your portlet, etc.,

    Possible ways to use the event attribute :

  5. If your action has to update an element on your client's interface, you must call addUIComponentToUpdateByAjax() at the end of the execute method:

    event.getRequestContext().addUIComponentToUpdateByAjax(uicomponent);
    

    The target component must be provided as parameter (the component that will be updated). We will come back on this later.

  6. You must create one inner action listener class for each Ajax call you want to handle on this portlet. All these classes must be declared in the configuration annotations of the main class, otherwise you will get an error.

  7. Done. Your portlet is ready to accept Ajax calls from your client.

All javascript in is managed by the file 02eXoresources:javascript/eXo/portal/PortalHttpRequest.js.

In this class, there are four functions/classes:

PortletResponse

PortalResponse

AjaxRequest

HttpResponseHandler

and 6 functions:

In addition to the content in this chapter, refer also to Section 6.2, “AJAX Framework” in order to better understand the communication between the Groovy Template and the portlet.

The configuration of a portlet is partly made with ComponentConfig annotations (others are ComponentConfigs, EventConfig, etc).

One of the parameters of this annotation is template. This is where the path to the template file associated with this portlet is defined.

To specify this parameter, add this statement to the configuration annotation.

For example, in src:/portlet/exoadmin/src/main/java/org/exoplatform/applicationregistry/webui/component/ is the UIApplicationForm.java file:

@ComponentConfig(
  lifecycle = UIFormLifecycle.class,
  template =  "system:/groovy/webui/form/UIFormWithTitle.gtmpl",
  events = {
    @EventConfig(listeners = UIApplicationForm.SaveActionListener.class),
    @EventConfig(phase = Phase.DECODE, listeners = UIApplicationForm.CancelActionListener.class)
  }
)

The path is in the "system" namespace. This is a reference to the portal webapp.

This webapp contains reusable groovy templates in the folder; src:/web/portal/src/main/webapp/groovy/webui/form/ .

Use the following steps to create a new template;

Component template files are composed in HTML code and groovy code blocks. There are a few things more that you need to know to fully link your portlet with your template.

To successfully link a portlet with a template, please ensure the following:

This chapter does not to refer to the Portlet API specification lifecycle but focuses on the UI framework.

This web framework has been developed specifically for and, while it is not necessary to use the native web framework to build portlets, all portlets packaged with are developed using this framework.

This consistency allows portlets to use several UI components that can be used in different abstracted contexts (such as the portal itself or some portlets).

The main entry point for configuring a portlet is in the portlet.xml file located in the portlet application WAR.

Each portlet built using the web framework must reference the PortletApplicationController .

The portlet configuration (such as the root component) is defined in configuration.xml. The path to this file is defined in the init-param "webui.configuration" of portlet.xml.

<portlet>
  <description xml:lang="EN">Content Portlet</description>
  <portlet-name>ContentPortlet</portlet-name>
  <display-name xml:lang="EN">Content Portlet</display-name>
  <portlet-class>org.exoplatform.webui.application.portlet.PortletApplicationController</portlet-class>    
    
  <init-param>
    <name>webui.configuration</name>
    <value>/WEB-INF/conf/portlet/content/ContentPortlet/webui/configuration.xml</value>
  </init-param>
</portlet>

The structure of the configuration.xml file is exactly the same as the webui-configuration.xml which was introduced in Section 5.1, “Portal Lifecycle”.

In the case of the content portlet it is formatted as:

<webui-configuration>
  <application> 
    <ui-component-root>org.exoplatform.content.webui.component.UIContentPortlet</ui-component-root>
    <state-manager>org.exoplatform.webui.application.portlet.ParentAppStateManager</state-manager>
  </application>
</webui-configuration>

The PortletApplicationController class extends the GenericPortlet class defined in the Portlet API specification.

All methods (like processAction() or render()) are delegated to the PortletApplication. The creation and caching inside the WebController object is shown in the example below:

/**
 * try to obtain the PortletApplication from the WebAppController.
 * 
 * If it does not exist a new PortletApplication object is created, init and cached in the
 * controller
 */
private PortletApplication getPortletApplication() throws Exception {
  PortalContainer container = PortalContainer.getInstance() ;
  WebAppController controller = 
    (WebAppController)container.getComponentInstanceOfType(WebAppController.class) ;
  PortletApplication application = controller.getApplication(applicationId_) ;
  if(application == null) {
    application = new PortletApplication(getPortletConfig()) ;
    application.onInit() ; 
    controller.addApplication(application) ;
  }
  return application ;
}

The code of the method in PortletApplication is described below. The business logic is shown in the javadoc:

/**
 * The processAction() method is the one modelled according to the Portlet API specification
 * 
 * The process is quite simple and here are te different steps done in the method:
 * 
 * 1) The current instance of the WebuiRequestContext (stored in a ThreadLocal in the class) is referenced
 * 2) A new request context of type PortletRequestContext (which extends the class WebuiRequestContext) is
 *    created as a child of the current context instance
 * 3) The new context is place inside the ThreadLocal and hence overides its parent one there, 
 *    only for the portlet request lifeciclye
 * 4) The method onStartRequest() is called in all the ApplicationLifecycle objects referenced in the webui 
 *    configuration XML file
 * 5) The StateManager object (in case of portlet it is an object of type ParentAppStateManager) is used to get the RootComponent
 *    also referenced in the XML configuration file
 * 6) The methods processDecode(UIApplication, WebuiRequestContext) and processAction(UIApplication, WebuiRequestContext) 
 *     are then called 
 * 7) Finally, a flag, to tell that the processAction phase was done, in the context is set to true and the parent
 *    context is restored in the Threadlocal
 */
public void processAction(ActionRequest req, ActionResponse res) throws Exception {
  WebuiRequestContext parentAppRequestContext =  WebuiRequestContext.getCurrentInstance() ;
  PortletRequestContext context = createRequestContext(req, res, parentAppRequestContext)  ;
  WebuiRequestContext.setCurrentInstance(context) ;
  try {      
    for(ApplicationLifecycle lifecycle : getApplicationLifecycle())  {
      lifecycle.onStartRequest(this, context) ;
    } 
    UIApplication uiApp = getStateManager().restoreUIRootComponent(context) ;
    context.setUIApplication(uiApp) ;
    processDecode(uiApp, context) ;
    if(!images/context.isResponseComplete() &&!images/ context.getProcessRender()) {
      processAction(uiApp, context) ;
    }
  } finally {
    context.setProcessAction(true) ;
    WebuiRequestContext.setCurrentInstance(parentAppRequestContext) ;
  }
}

The PortletRequestContext extends the WebuiRequestContext class and acts as a wrapper on all the portlet request information:

/**
 * In this method we try to get the PortletRequestContext object from the attribute map of the parent 
 * WebuiRequestContext. 
 * 
 * If it is not cached then we create a new instance, if it is cached then we init it with the correct
 * writer, request and response objects
 * 
 * We finally cache it in the parent attribute map
 * 
 */
private PortletRequestContext createRequestContext(PortletRequest req, PortletResponse res,
                                                  WebuiRequestContext parentAppRequestContext) throws IOException {
  String attributeName = getApplicationId() + "$PortletRequest" ;
  PortletRequestContext context = 
    (PortletRequestContext) parentAppRequestContext.getAttribute(attributeName) ;
  Writer w  = null ;       
  if(res instanceof  RenderResponse){
    RenderResponse renderRes = (RenderResponse)res;
    renderRes.setContentType("text/html; charset=UTF-8");      
    w = renderRes.getWriter() ; 
  }
  if(context!images/= null) {
    context.init(w, req, res) ;
  } else {
    context =  new PortletRequestContext(this, w, req, res) ;
    parentAppRequestContext.setAttribute(attributeName, context) ;
  }
  context.setParentAppRequestContext(parentAppRequestContext) ;
  return context;
}

In the PortletApplication, the line;

UIApplication uiApp = getStateManager().restoreUIRootComponent(context);

asks the StateManager defined for the portlet to get the UI root component. In the case of a portlet the root component must extend UIPortletApplication.

public class ParentAppStateManager extends StateManager {
  
  /**
   * This method simply delegate the call to the same method of the parent WebuiRequestContext
   */
  @SuppressWarnings("unchecked")
  public UIApplication restoreUIRootComponent(WebuiRequestContext context) throws Exception {
    WebuiRequestContext pcontext = (WebuiRequestContext)  context.getParentAppRequestContext() ;
    return pcontext.getStateManager().restoreUIRootComponent(context) ;
  }

Hence this is the PortalStateManager that will also handle the extraction of the root component.

public UIApplication restoreUIRootComponent(WebuiRequestContext context) throws Exception {
  context.setStateManager(this) ;
  WebuiApplication app  = (WebuiApplication)context.getApplication() ;
  
  /*
   * If the request context is of type PortletRequestContext, we extract the parent context which will
   * allow to get access to the PortalApplicationState object thanks to the session id used as the key for the
   * syncronised Map uiApplications
   */
  if(context instanceof PortletRequestContext) {
    WebuiRequestContext preqContext = (WebuiRequestContext) context.getParentAppRequestContext() ;
    PortalApplicationState state = uiApplications.get(preqContext.getSessionId()) ;
    PortletRequestContext pcontext = (PortletRequestContext) context ;
    String key =  pcontext.getApplication().getApplicationId() ;
    UIApplication uiApplication =  state.get(key) ;
    if(uiApplication!images/= null)  return uiApplication;
    synchronized(uiApplications) {
      ConfigurationManager cmanager = app.getConfigurationManager() ;
      String uirootClass = cmanager.getApplication().getUIRootComponent() ;
      Class type = Thread.currentThread().getContextClassLoader().loadClass(uirootClass) ;
      uiApplication = (UIApplication)app.createUIComponent(type, null, null, context) ;     
      state.put(key, uiApplication) ;
    }
    return uiApplication ;
  }
}

The render method business logic is quite similar to processAction().

/**
 * The render method business logic is quite similar to the processAction() one.
 * 
 * 1) A PortletRequestContext object is created (or extracted from the cache if it already exists) 
 *    and initialized
 * 2) The PortletRequestContext replaces the parent one in the WebuiRequestContext ThreadLocal object
 * 3) If the portal has already called the portlet processAction() then the call to all onStartRequest of
 *    the ApplicationLifecycle has already been made, otherwise we call them
 * 4) The ParentStateManager is also used to get the UIApplication, as we have seen it delegates the call 
 *    to the PortalStateManager which caches the UI component root associated with the current application
 * 5) the processRender() method of the UIPortletApplucaton is called
 * 6) Finally, the method onEndRequest() is called on every ApplicationLifecycle referenced in the portlet
 *    configuration XML file and the parent WebuiRequestContext is restored
 *    
 */
public  void render(RenderRequest req,  RenderResponse res) throws Exception {    
  WebuiRequestContext parentAppRequestContext =  WebuiRequestContext.getCurrentInstance() ;
  PortletRequestContext context = createRequestContext(req, res, parentAppRequestContext)  ;
  WebuiRequestContext.setCurrentInstance(context) ;
  try {
    if(!context.hasProcessAction()) {
      for(ApplicationLifecycle lifecycle : getApplicationLifecycle())  {
        lifecycle.onStartRequest(this, context) ;
      }
    }      
    UIApplication uiApp =  getStateManager().restoreUIRootComponent(context) ;
    context.setUIApplication(uiApp) ;
    if(!context.isResponseComplete()) {
      UIPortletApplication uiPortletApp = (UIPortletApplication)uiApp;
      uiPortletApp.processRender(this, context) ;
    }
    uiApp.setLastAccessApplication(System.currentTimeMillis()) ;
  } finally {
    try {
      for(ApplicationLifecycle lifecycle :  getApplicationLifecycle()) {
        lifecycle.onEndRequest(this, context) ;
      }
    } catch (Exception exception){
  	log.error("Error while trying to call onEndRequest of the portlet ApplicationLifecycle", 
  		exception);
    }
    WebuiRequestContext.setCurrentInstance(parentAppRequestContext) ;
  }
}

The following is the processRender() call made on the UIPortletApplication:

/**
 * The default processRender for an UIPortletApplication handles two cases:
 * 
 *   A. Ajax is used 
 *   ----
 *     If Ajax is used and that the entire portal should not be re rendered, then an AJAX fragment is 
 *     generated with information such as the portlet id, the portlet title, the portlet modes, the window 
 *     states as well as the HTML for the block to render
 *   
 *   B. A full render is made
 *   ----
 *      a simple call to the method super.processRender(context) which will delegate the call to all the 
 *      Lifecycle components
 *   
 */
public void  processRender(WebuiApplication app, WebuiRequestContext context) throws Exception {
  WebuiRequestContext pContext = (WebuiRequestContext)context.getParentAppRequestContext();
  if(context.useAjax() &&!images/pContext.getFullRender()) {
    Writer w =  context.getWriter() ;
    
    Set<UIComponent> list = context.getUIComponentToUpdateByAjax() ;
    if(list!images/= null) {
      if(getUIPopupMessages().hasMessage()) context.addUIComponentToUpdateByAjax(getUIPopupMessages()) ;
      for(UIComponent uicomponent : list) {
        renderBlockToUpdate(uicomponent, context, w) ;
      }
      return ;
    }
  }
  super.processRender(context) ;    
}

The Java Community Process (JCP) uses Java Specification Requests (JSRs) to define proposed specifications and technologies designed for the Java platform.

The Portlet Specifications aim at defining portlets that can be used by any JSR-168 (Portlet 1.0) or JSR-286 (Portlet 2.0) portlet container.

Most Java EE (Enterprise Edition) portals include at least one compliant portlet container, and is no exception. In fact, includes a container that supports both versions.

This chapter gives a brief overview of the Portlet Specifications but portlet developers are strongly encouraged to read the JSR-286 Portlet Specification .

is fully JSR-286 compliant. Any JSR-168 or JSR-286 portlet operates as it is mandated by the respective specifications inside the portal.

The tutorials contained in this chapter are targeted toward portlet developers. It is also recommend that developers read and understand the JSR-286 Portlet Specification .

Maven

This example is using Maven to compile and build the web archive. Maven versions can be downloaded from maven.apache.org

This section describes how to deploy a portlet in . A sample portlet called SimplestHelloWorld is located in the examples directory at the root of your binary package. This sample is used in the following examples.

Below is the SimplestHelloWorldPortlet/src/main/java/org/gatein/portal/examples/portlets/SimplestHelloWorldPortlet.java Java source:

package org.gatein.portal.examples.portlets;


import java.io.IOException;
import java.io.PrintWriter;
import javax.portlet.GenericPortlet;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
(1)public class SimplestHelloWorldPortlet extends GenericPortlet
{
   public void doView(RenderRequest request, 
(2)                       RenderResponse response) throws IOException
   {
(3)      PrintWriter writer = response.getWriter();
(4)      writer.write("Hello World !");
(5)      writer.close();
   }
}
1

All portlets must implement the javax.portlet.Portlet interface. The portlet API provides a convenient implementation of this interface.

The javax.portlet.Portlet interface uses the javax.portlet.GenericPortlet class which implements the Portlet render method to dispatch to abstract mode-specific methods. This makes it easier to support the standard portlet modes.

Portlet render also provides a default implementation for the processAction, init and destroy methods. It is recommended to extend GenericPortlet for most cases.

2

If only the view mode is required, then only the doView method needs to be implemented. The GenericPortletrender implementation calls our implementation when the view mode is requested.

3

Use the RenderResponse to obtain a writer to be used to produce content.

4

Write the markup to display.

5

Closing the writer.

requires certain descriptors to be included in a portlet WAR file. These descriptors are defined by the Jave EE (web.xml) and Portlet Specification (portlet.xml).

Below is an example of the SimplestHelloWorldPortlet/WEB-INF/portlet.xml file. This file must adhere to its definition in the JSR-286 Portlet Specification. More than one portlet application may be defined in this file:

<portlet-app xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd"
   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"
   version="2.0">
   <portlet>
      <portlet(1)-name>SimplestHelloWorldPortlet</portlet-name>
      <portlet(2)-class>
         org.gatein.portal.examples.portlets.SimplestHelloWorldPortlet
      </portlet-class>
      <support(3)s>
        <mime-type>text/html</mime-type>
      </supports>
      <portlet(4)-info>
          <title>Simplest Hello World Portlet</title>
      </portlet-info>
   </portlet>
</portlet-app>
1

Define the portlet name. It does not have to be the class name.

2

The Fully Qualified Name (FQN) of your portlet class must be declared here.

3

The <supports> element declares all of the markup types that a portlet supports in the render method. This is accomplished via the <mime-type> element, which is required for every portlet.

The declared MIME types must match the capability of the portlet. It allows administrators to pair which modes and window states are supported for each markup type.

This does not have to be declared as all portlets must support the view portlet mode.

Use the <mime-type> element to define which markup type the portlet supports. In the example above this is text/html. This section tells the portal to only output HTML.

4

When rendered, the portlet's title is displayed as the header in the portlet window, unless it is overridden programmatically. In the example above the title would be Simplest Hello World Portlet .

This section discusses:

The code below is from the JSPHelloUser/src/main/java/org/gatein/portal/examples/portlets/JSPHelloUserPortlet.java Java source. It is split in different pieces.

package org.gatein.portal.examples.portlets;


import java.io.IOException;
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.GenericPortlet;
import javax.portlet.PortletException;
import javax.portlet.PortletRequestDispatcher;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import javax.portlet.UnavailableException;
public class JSPHelloUserPortlet extends GenericPortlet
{
   
   public void doView(RenderRequest request, RenderResponse response)
(1)       throws PortletException, IOException
   {
      String sYourName = (String) request.getParameter("yourname");
(2)      if (sYourName != null)
      {
         request.setAttribute("yourname", sYourName);
         PortletRequestDispatcher prd = 
(3)            getPortletContext().getRequestDispatcher("/jsp/hello.jsp");
(4)         prd.include(request, response);
      }
      else
      {
         PortletRequestDispatcher prd = getPortletContext().getRequestDispatcher("/jsp/welcome.jsp");
         prd.include(request, response);
      }
   }
...
1

Override the doView method (as in the first tutorial).

2

This entry attempts to obtain the value of the render parameter named yourname. If defined it should redirect to the hello.jsp JSP page, otherwise to the welcome.jsp JSP page.

3

Get a request dispatcher on a file located within the web archive.

4

Perform the inclusion of the markup obtained from the JSP.

As well as the VIEW portlet mode, the specification defines two other modes; EDIT and HELP.

These modes need to be defined in the portlet.xml descriptor. This will enable the corresponding buttons on the portlet's window.

The generic portlet that is inherited dispatches the different views to the methods: doView , doHelp and doEdit.

...

   protected void doHelp(RenderRequest rRequest, RenderResponse rResponse) throws PortletException, IOException,
         UnavailableException
   {
      rResponse.setContentType("text/html");
      PortletRequestDispatcher prd = getPortletContext().getRequestDispatcher("/jsp/help.jsp");
      prd.include(rRequest, rResponse);
   }
   protected void doEdit(RenderRequest rRequest, RenderResponse rResponse) throws PortletException, IOException,
         UnavailableException
   {
      rResponse.setContentType("text/html");
      PortletRequestDispatcher prd = getPortletContext().getRequestDispatcher("/jsp/edit.jsp");
      prd.include(rRequest, rResponse);
   }
...

Portlet calls happen in one or two phases. One when the portlet is rendered and two when the portlet is actioned then rendered.

An action phase is a phase where some state changes. The render phase will have access to render parameters that will be passed each time the portlet is refreshed (with the exception of caching capabilities).

The code to be executed during an action has to be implemented in the processAction method of the portlet.

...

(1)         public void processAction(ActionRequest aRequest, ActionResponse aResponse) throws PortletException, IOException,
         UnavailableException
   {
(2)      String sYourname = (String) aRequest.getParameter("yourname");
(3)      aResponse.setRenderParameter("yourname", sYourname);
   }
...
1

processAction is the method from GernericPorlet to override for the action phase.

2

Here the parameter is retrieved through an action URL .

3

The value of yourname is kept to make it available in the rendering phase. The previous line simply copies an action parameters to a render parameter for this example.

The help.jsp and edit.jsp files are very simple. Note that CSS styles are used as defined in the portlet specification. This ensures that the portlet will render well within the theme and across portal vendors.


<div class="portlet-section-header">Help mode</div>
<div class="portlet-section-body">This is the help mode, a convenient place to give the user some help information.</div>

<div class="portlet-section-header">Edit mode</div>
<div class="portlet-section-body">This is the edit mode, a convenient place to let the user change his portlet preferences.</div>

The landing page contains the links and form to call our portlet:

<%@ taglib uri(1)="http://java.sun.com/portlet" prefix="portlet" %>

<div class="portlet-section-header">Welcome !</div>

<br/>

<div class="portlet-font">Welcome on the JSP Hello User portlet,
my name is GateIn Portal. What's yours ?</div>

<br/>

<div class="portlet-font">Method 1: We simply pass the parameter to the render phase:<br/>
<a href="<port(2)let:renderURL><portlet:param name="yourname" value="John Doe"/>
                </portlet:renderURL>">John Doe</a></div>

<br/>

<div class="portlet-font">Method 2: We pass the parameter to the render phase, using valid XML:
Please check the source code to see the difference with Method 1.
<portlet:rende(3)rURL var="myRenderURL">
    <portlet:param name="yourname" value='John Doe'/>
</portlet:renderURL>
<br/>
<a href="<%= m(4)yRenderURL %>">John Doe</a></div>

<br/>

<div class="portlet-font">Method 3: We use a form:<br/>

<portlet:actio(5)nURL var="myActionURL"/>
<form action="(6)<%= myActionURL %>" method="POST">
         <span class="portlet-form-field-label">Name:</span>
         <input class="portlet-form-input-field" type="text" name="yourname"/>
         <input class="portlet-form-button" type="Submit"/>
</form>
</div>
1

The portlet taglib, needs to be declared.

2

The first method showed here is the simplest one. portlet:renderURL will create a URL that calls the render phase of the current portlet and append the result at the place of the markup (within a tag). A parameter is also added directly to the URL.

3

In this method the var attribute is used. This avoids having one XML tag within another. Instead of printing the url the portlet:renderURL tag will store the result in the referenced variable ( myRenderURL).

4

The variable myRenderURL is used like any other JSP variable.

5

The third method mixes form submission and action request. Again, a temporary variable is used to put the created URL into.

6

The action URL is used in HTML form.

In the third method the action phase is triggered first then the render phase is triggered, which outputs some content back to the web browser based on the available render parameters.

In order to write a portlet using JSF a 'bridge' is needed. This software allows developers to write a portlet application as if it was a JSF application. The bridge then negotiates the interactions between the two layers.

An example of the JBoss Portlet Bridge is available in examples/JSFHelloUser. The configuration is slightly different from a JSP application. This example can be used as a base to configure instead of creating a new application.

As in any JSF application, the file faces-config.xml is required. It must contain the following information:


<faces-config>
...
    <application>
      <view-handler>org.jboss.portletbridge.application.PortletViewHandler</view-handler>
      <state-manager>org.jboss.portletbridge.application.PortletStateManager</state-manager>
   </application>
...
</faces-config>

The portlet bridge libraries must be available and are usually bundled with the WEB-INF/lib directory of the web archive.

The other difference compare to a regular portlet application, can be found in the portlet descriptor. All details about it can be found in the JSR-301 specification that the JBoss Portlet Bridge implements.

In WEB-INF, create file portlet.xml :


<?xml version="1.0" encoding="UTF-8"?>
<portlet-app version="1.0" xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd"> 
  <portlet>
    <description xml:lang="EN">Test Portlet Romain</description>
    <portlet-name>TestRomain</portlet-name>
    <display-name xml:lang="EN">Test Portlet Romain</display-name>
    <portlet-class>org.exoplatform.webui.application.portlet.PortletApplicationController</portlet-class>
    <init-param>
      <name>webui.configuration</name>
      <!-- must match the path to configuration file -->
      <value>/WEB-INF/conf/portlet/testPortletRomain/configuration.xml</value>
    </init-param>    
    <expiration-cache>0</expiration-cache>
    <supports>
      <mime-type>text/html</mime-type>
      <portlet-mode>help</portlet-mode>
    </supports>
    <supported-locale>en</supported-locale>
    <resource-bundle>locale.testRomainPortlet</resource-bundle>     
    <portlet-info>
      <title>TestPortletRomain</title>
      <short-title>TestPortlet</short-title>
      <keywords>test</keywords>
    </portlet-info>     
  </portlet>
</portlet-app>

Now, we will add a popup which say "HelloWorld" when you click on the button.

First, create the groovy template of the popup : in webapp/groovy/testRomain/portlet, create UIHelloWorldPopupContent.gtmpl :

<div id="<%=uicomponent.getId();%>">
	HelloWorld in a popup
</div>

In java/testRomain/portlet/component, create the java file for the popup look like : {code} package testRomain.portlet.component;

package testRomain.portlet.component;

import org.exoplatform.webui.config.annotation.ComponentConfig;
import org.exoplatform.webui.core.UIComponent;
import org.exoplatform.webui.core.lifecycle.UIApplicationLifecycle;
@ComponentConfig(
   lifecycle = UIApplicationLifecycle.class,
   template = "app:/groovy/testRomain/portlet/UIHelloWorldPopupContent.gtmpl"
  )
public class UIHelloWorldPopupContent extends UIComponent {
  public UIHelloWorldPopupContent() throws Exception {
  }
}

In UITestRomainPortlet.java, we will create the popup at the portlet creation (in the constructor) :

public UITestRomainPortlet() throws Exception {

  UIPopupWindow popup = addChild(UIPopupWindow.class, null, null);
  popup.setWindowSize(400, 300);
  
  UIHelloWorldPopupContent popupContent = createUIComponent(UIHelloWorldPopupContent.class, null, null);
  popup.setUIComponent(popupContent);
  popup.setRendered(false);

At the beginning, we set the popup not visible. As you see, we add a children to the Portlet. So, if we want to see the content of it, we must add this in UITestPortletRomain.gtmpl :

<% uicomponent.renderChildren(); %>

This makes the portlet generate the content of all child components.

Change the treatment of the event, replace the println by :

public static class OpenPopupActionListener extends EventListener<UITestRomainPortlet> {

  public void execute(Event<UITestRomainPortlet> event) throws Exception {
    UITestRomainPortlet portlet = event.getSource();
    UIPopupWindow popup = portlet.getChild(UIPopupWindow.class);
    popup.setRendered(true);
    popup.setShow(true);
  }
}

When user clicks on the button, the popup is shown.

Redeploy the portlet and click on the button. You will see "HelloWorld in a popup" in a popup. If you don't change in the portlet, try to redeploy and reboot the tomcat server.