Applications play an important role in each eXo service, so it is necessary for you to further understand about them.

This chapter includes the following main topics:

  • Integrate an application

    Instructions on how to add an application (especially a portlet) to your portal's paces.

  • Develop your own application

    Instructions on how to develop a gadget for eXo Platform, and information about Portlet Bridges.

  • Extend eXo applications

    Concept and mechanism of UI Extension framework which allows the customization and extensibility of eXo applications through simple plugins.

To add a portlet to one of your portal's pages, you should configure the pages.xml file located at /war/src/main/webapp/WEB-INF/conf/sample-ext/portal/portal/classic/.

Here is an example of the portlet configuration in the pages.xml file:

Details:

XML tag name Description
application-ref The name of the webapp that contains the portlet.
portlet-ref The name of the portlet.
title The title of the page.
access-permission Define who can access the portlet.
show-info-bar Show the top bar with the portlet title.
show-application-state Show the collapse/expand icons.
show-application-mode Show the change portlet mode icon.
preferences Contain a list of preferences specific to each portlet. Each preference has a name and a value. You can also lock it by setting the read-only element to "true". To learn more, refer to eXo JCR and Extension Services Reference.

See also

  • Develop a gadget for eXo Platform

    Introduction to the resources which can be shared for all gadgets and their categories, instructions on how to apply for a gadget and to customize the gadget thumbnail.

  • Portlet Bridges

    Adapter for a web framework to the portlet container runtime. It works ideally with framework that does not expose the servlet container with the limited support for the full portlet API.

See also

Because a gadget is basically an independent HTML content, the gadget UI, such as layout, font, color may be different. Thus, making consistent in the look and feel of all eXo Platform gadgets is very important. In this part, it is assumed that developers have already known how to write a gadget in eXo Platform. The information here helps developers make a consistent look and feel with eXo Platform skin, even when this skin may be changed in the future.

Note

To get more information on how to develop gadgets, see the Gadget development and Develop gadgets via a powerful web-based IDE of eXo Platform sections.

To achieve the consistent look and feel, you have to collect the common features of all gadgets as much as possible and put in a place where it can be shared for all gadgets. You will use exo-gadget-resources for this purpose. It is a .war file that contains commonly used static resources (stylesheets, images, JavaScript libraries, and more) available for all gadgets in eXo Platform at runtime:

The resources are divided into 2 categories: skin and script.

Skin: is the place for the shared stylesheets of the gadgets (exo-gadget/gadget-common.css) and other third-party components styles adapted to the eXo Platform skin (jqPlot, Flexigrid, and more). This is a copy of the component's original CSS with some modifications to match the eXo Platform's skin. You can find this original file at the component's folder under exo-gadget-resources/script , then link to it or make your own copy (put it in your gadget's folder and refer to it in gadget's .xml file) to suit your need.

The gadget-common.css file is the main place for the global stylesheets. When the eXo Platform skin is changed, updating stylesheets in this file will affect all gadgets skins accordingly. In this file, you will define stylesheets applied for all gadgets, such as gadget title, gadget body, fonts, colors, tables, and some commonly used icons, such as drop-down arrow, list bullet, setting button, and more.

For example:

Script: is the place for commonly used third-party JavaScript libraries (e.g: jQuery and its plugins) and a library of useful utility scripts (the utils folder).

jQuery and plugins:

(Here you should keep the latest and several versions of jQuery because some plugins may not work with the latest version. Several versions of a plugin are also kept).

The utilities scripts:

  • utils/pretty.date.js: Calculate the difference from a point of time in the past to the present and display "4 months 3 weeks ago", for example.

A gadget should use static resources available in exo-gadget-resources instead of including them in their own package. This helps reduce packaging size, avoid duplication (considering that every gadget includes a version of jQuery is in its own package) and take advantages of automatic skin changing/updating when the resources of exo-gadget-resources are updated to the new eXo Platform skin. To make it work, the applied gadget must use the CSS classes defined in gadget-common.css (at least for the gadget title) like the sample gadget below:

The sample gadget:

The sample user settings of a gadget

The following gadget gives the demo of a user settings screen which uses eXo Platform standard icons (setting button, list item bullet, and more) that are defined in the gadget-common.css.


<Module>
<ModulePrefs title="Setting demo"> 
  <Require feature="dynamic-height"/> 
  <Require feature="setprefs"/> 
</ModulePrefs>  
<Content type="html"> 
  <head> 
    <link href="/exo-gadget-resources/skin/exo-gadget/gadget-common.css" rel="stylesheet" type="text/css"/> 
    <style type="text/css"> 
      .SettingButton:hover {cursor:pointer;} 
    </style>  
    <script language="javascript" src="/exo-gadget-resources/script/jquery/1.6.2/jquery.min.js" type="text/javascript"/> 
    <script language="javascript" type="text/javascript"> 
 
      $(function(){ 
        var prefs = new gadgets.Prefs(); 
        var defaultNumItems = 3; 

        function displayItems(){ 
          var numItems = prefs.getInt("numItems") || defaultNumItems; 
          $("#content").html(""); 
          for(i=0; i&lt;=numItems; i++) { 
            $("#content").append("&lt;div class='IconLink'&gt;Item " + (i+1) + "&lt;/div&gt;");    (3)
          } 
          gadgets.window.adjustHeight($(".GadCont").get(0).offsetHeight); 
        }      
        
        $(".SettingButton").live("click", function(){ 
          $("#txtNumItems").val(prefs.getInt("numItems") || defaultNumItems); 
          $("#setting").toggle(); 
          gadgets.window.adjustHeight($(".GadCont").get(0).offsetHeight); 
        }); 

        $("#btnOk").live("click", function(){ 
          var sNumItems = $("#txtNumItems").val(); 
          prefs.set("numItems", parseInt(sNumItems) || defaultNumItems); 
          $("#setting").hide(); 
          displayItems(); 
        }); 

        $("#btnCancel").live("click", function(){ 
          $("#setting").hide(); 
          gadgets.window.adjustHeight($(".GadCont").get(0).offsetHeight); 
        }); 

        displayItems(); 
      }); 
 
    </script>  
  </head> 
  <body> 
    <div class="UIGadgetThemes"> 
      <div class="TitGad ClearFix"> 
        <div class="ContTit"> 
          Setting demo 
          <div class="SettingButton" style="display:block; width:20px; height:20px"/>   (1)
        </div> 
      </div> 
      <div class="GadCont"> 
        <div id="setting" style="display:none;">   (2)
          <label for="txtNumItems">Num of items</label> 
          <input id="txtNumItems" type="text"/>                                       
          <input id="btnOk" type="button" value="OK"/> 
          <input id="btnCancel" type="button" value="Cancel"/> 
          <hr/> 
        </div> 
        <div id="content"/> 
      </div> 
    </div> 
  </body> 
</Content> 
</Module>

  • UI Extension components

    Necessary information about UIExtensionManager, UIExtensionPlugin, introduction to UI Extension definition and its class, parent UI components, and details about filters of each UI Extension.

  • Mechanism

    Details about the working process of each UI Extension, including: setting up, loading and activating.

What is UI Extension framework?

UI Extension is an extension of UI Component. As you know, extension is an object that contains programming for extending the capabilities of data available to a more basic program. Here, UI Extension helps expanding the dynamic children of UI Component. With UI Extension, you can add, change or remove a lot of children in UI Component more easily than in traditional ways.

Why use UI Extension framework?

It is simple for you and your team to control applications containing few components that are all constant. But when you start an application which contains a lot of components, transactions, filters and permissions on each component, it is really a disaster. As each developer may handle problems in their own way, it also likely raises the convention problem. Thus, UI Extension framework was created to solve the management dynamic components on the applications and free developers from controlling too many of them.

The main goals of this framework are:

  • Create simple child UI Components.

  • Apply a filter on each component for a variety of purposes more easily.

  • Add or remove extensions simply by configuration.

See also

UIExtensionManager

This class is used to manage all extensions available in the system. The target is to create the ability to add a new extension dynamically without changing anything in the source code. UIExtensionManager is implemented by UIExtensionManagerImpl.


<component>
  <key>org.exoplatform.webui.ext.UIExtensionManager</key>
  <type>org.exoplatform.webui.ext.impl.UIExtensionManagerImpl</type>
</component>

UIExtensionPlugin

This class allows you to define new extensions in the configuration file dynamically (for example: configuration.xml). As you want UIExtensionManager to manage every extension, you have to plug UIExtensionPlugin into it:


<external-component-plugins>
    <target-component>org.exoplatform.webui.ext.UIExtensionManager</target-component>
    <component-plugin>
      <name>add.action</name>
      <set-method>registerUIExtensionPlugin</set-method>
      <type>org.exoplatform.webui.ext.UIExtensionPlugin</type>
        ...
    </component-plugin>
</external-component-plugins>

Definition of UI Extensions

Each UI Extension is defined as an object param:


...
<object-param>
          <name>EditPage</name>
          <object type="org.exoplatform.webui.ext.UIExtension">
            <field name="type"><string>org.exoplatform.wiki.UIPageToolBar</string></field>
            <field name="rank"><int>300</int></field>
            <field name="name"><string>EditPage</string></field>
            <field name="component"><string>org.exoplatform.wiki.webui.control.action.EditPageActionComponent</string></field>
          </object>
 </object-param>
...

In which:

  • Name: the extension's name.

  • Object Type: point to the UI Extension lib class.

    • Type: the "parent" UI component which is extended by your UI Extension.

    • Rank: used to sort by Collection of UI Extension.

    • Component: point to the UI Extension definition class.

UI Extension Definition class

This class is used to define filters, actions and templates of UI Extension:

@ComponentConfig( 

  events =
{(listeners = EditPageActionComponent.EditPageActionListener.class);}) 
  public class EditPageActionComponent extends UIComponent { 
  private static final List<UIExtensionFilter> FILTERS = Arrays.asList(new UIExtensionFilter[] { new IsViewModeFilter() }); 
  @UIExtensionFilters 
   public List<UIExtensionFilter> getFilters() {
    return FILTERS;
}
  public static class EditPageActionListener extends UIPageToolBarActionListener<EditPageActionComponent> {
    @Override
    protected void processEvent(Event<EditPageActionComponent> event) throws Exception {
     ...
      super.processEvent(event);
    }
  } 
...

Parent UI Component

This is what your UI Extension will be added to (in this example, the parent UI Componet is UIPageToolBar). All extensions of this component are got by UIExtensionManager.

UIExtensionManager manager = getApplicationComponent(UIExtensionManager.class);

 
List<UIExtension> extensions = manager.getUIExtensions(EXTENSION_TYPE);
 public List<ActionComponent> getActions() throws Exception {
    ....
    List<UIExtension> extensions = manager.getUIExtensions(EXTENSION_TYPE);
    if (extensions != null) {
      for (UIExtension extension : extensions) {
        UIComponent component = manager.addUIExtension(extension, context, this);
// Child UI Component has been made by UI Extension
// It's available to use now
        ...
      }
    }
    return activeActions;
  }

Internal filter

Each UI Extension has a list of filters depending on variety of purposes. It indicates which UI Extension is accepted and which is denied. You are free to create your own filter extended from UIExtensionAbstractFilter. Internal filters are a part of the business logic of your component. For example, if your component is only dedicated to articles, you will add an internal filter to your component that will check the type of the current document.

public class IsViewModeFilter extends UIExtensionAbstractFilter { 

   public IsViewModeFilter(String messageKey) {
    super(messageKey, UIExtensionFilterType.MANDATORY);
  } 
  @Override
  public boolean accept(Map<String, Object> context) throws Exception {
    UIWikiPortlet wikiPortlet = (UIWikiPortlet) context.get(UIWikiPortlet.class.getName());
    return(wikiPortlet.getWikiMode() == WikiMode.VIEW||wikiPortlet.getWikiMode() == WikiMode.VIEWREVISION);
  } 
  @Override
  public void onDeny(Map<String, Object> context) throws Exception {
    // TODO Auto-generated method stub 
  }

Your filter will define which type of filter it belongs to (in UIExtensionFilterType). There are 4 types:

Types Description
MANDATORY Check if the action related to the extension can be launched and if the component related to the extension can be added to the WebUI tree. This filter is required to launch the action and add the component related to the extension to the WebUI tree. If it succeeds, you need to check the other filters. If it fails, you need to stop.
REQUISITE Check if the action related to the extension can be launched. This filter is required to launch the action to the WebUI tree. If it succeeds, you need to check the other filters. If it fails, you need to stop.
REQUIRED Check if the action related to the extension can be launched and can be used for adding warnings. This filter is required to launch the action. If it succeeds or fails, you need to check the other filters.
OPTIONAL Check if the action related to the extension can be launched and can be used for the auditing purpose. This filter is not required to launch the action. If it succeeds or fails, you need to check the other filters.

There are 2 conditions for filtering: Accept and onDeny.

  • Accept: Describe the "Accept" condition, and how an UI Extension can accept by a context.

  • onDeny: What you will do after the filter denies an UI Extension by a specific context (generating a message for pop-up form, for example).

You have known how and where the filter is put in an UI Component, but when it is gonna fire?

It falls into 2 situations: when you get it and when it is action fire. Thus, you should ensure that your UI Extension is always trapped by its filter.

External filter

External filters are mainly used to add new filters that are not related to the business logic to your component. A good example is the UserACLFilter which allows you to filter by access permissions.

For example, to make the EditPage action only be used by manager:/platform/administrators, do as follows:

  • Create an external filter:

public class UserACLFilter implements UIExtensionFilter { 

  /**
   * The list of all access permissions allowed
   */
  protected List<String> permissions; 
  /**
   * {@inheritDoc}
   */
  public boolean accept(Map<String, Object> context) throws Exception {
    if (permissions == null || permissions.isEmpty()) {
      return true;
    }
    ExoContainer container = ExoContainerContext.getCurrentContainer();
    UserACL userACL = (UserACL) container.getComponentInstance(UserACL.class);
    for (int i = 0, length = permissions.size(); i < length; i++) {
      String permission = permissions.get(i);
      if (userACL.hasPermission(permission)) {
        return true;
      }
    }
    return false;
  }
 
  /**
   * {@inheritDoc}
   */
  public UIExtensionFilterType getType() {
    return UIExtensionFilterType.MANDATORY;
  }
 
  /**
   * {@inheritDoc}
   */
  public void onDeny(Map<String, Object> context) throws Exception {}
}
  • Add the external filter to an UI Extension in the configuration.xml file:


<object-param>
  <name>EditPage</name>
  <object type="org.exoplatform.webui.ext.UIExtension">
    <field name="type"> <string>org.exoplatform.wiki.UIPageToolBar</string> </field>
 <field name="rank"><int>300</int></field>
    <field name="name"> <string>EditPage</string> </field>
    <field name="component"><string>org.exoplatform.wiki.webui.control.action.EditPageActionComponent</string> </field>
    <!-- The external filters -->
    <field name="extendedFilters">
      <collection type="java.util.ArrayList">
        <value>
          <object type="org.exoplatform.webui.ext.filter.impl.UserACLFilter">
            <field name="permissions">
              <collection type="java.util.ArrayList">
                <value>
                  <string>manager:/platform/administrators</string>
                </value>
              </collection>
            </field>
          </object>
        </value>
      </collection>
    </field>
  </object>
</object-param>

The UI Extension's working process is divided into 3 phases:

Setting up

At first, you must add Dependencies to pom.xml. In this phase, you are going to install all elements of UI Extension framework in the configuration.xml file:

Loading

UIExtensionPlugin is responsible for looking up all UI Extension definitions, thus you can use it to obtain all UI Extensions, then plug it into UIExtensionManager. At present, all UI Extensions in your project will be managed by UIExtensionManager. Now you can get UI Extensions everywhere by invoking the getUIExtensions(String objectType) method.

In the UI Component class, implement a function which:

The addUIExtension() method is responsible for adding extensions to an UI Component. It depends on:

Activating

The final step is to present UI Extension in a template.

As all UI Extensions are presently becoming children of UI Component, you can implement UI Component's action thanks to UI Extension's action. For example:

Copyright © 2009-2012. All rights reserved. eXo Platform SAS