This chapter provides you with the basic knowledge of portal development via the following topics:

  • Skin components

    Overall information about 3 main components of a complete skin, including Portal Skin, Window Styles and Portlet Skins.

  • Skin selection

    Ways to select a skin via the User Interface and set the default skin within the configuration file.

  • Skins in page markups

    Introduction to the skins in page markups with 2 main types of CSS links.

  • Skin Service

    Knowledge of Skin Service, including skin configuration and resource request filter.

  • Default Skin

    Details of main files associated with the default skin, including gatein-resources.xml, web.xml, and Stylesheet.css.

  • Create new skins

    Instructions on how to create a new portal skin, windows style, portlet skin and portlet specification CSS class.

  • Tips and tricks

    Knowledge of CSS techniques and tips for easier CSS debugging.

GateIn 3.2 provides robust skinning support for the entire portal User Interface (UI). This includes support for skinning all of the common portal elements and being able to provide custom skins and window decoration for individual portlets. It is designed to common graphic resource reuse and ease of development.

See also

The complete skinning of a page can be decomposed into three main parts:

The GateIn 3.2 skin contains CSS styles for the portal's components but also shares components that may be reused in portlets. When GateIn 3.2 generates a portal page markup, it inserts the stylesheet links in the page's head tag.

There are two main types of CSS links that will appear in the head tag: a link to the portal skin CSS file and a link to the portlet skin CSS files.

In the code fragment below, you can see two types of links:


<head>
...
<!-- The portal skin -->
<link id="CoreSkin" rel="stylesheet" type="text/css" href="/eXoResources/skin/Stylesheet.css" />

<!-- The portlet skins -->
<link id="web_FooterPortlet" rel="stylesheet" type="text/css" href= "/web/skin/portal/webui/component/UIFooterPortlet/DefaultStylesheet.css" />
<link id="web_NavigationPortlet" rel="stylesheet" type="text/css" href= "/web/skin/portal/webui/component/UINavigationPortlet/DefaultStylesheet.css" />
<link id="web_HomePagePortlet" rel="stylesheet" type="text/css" href= "/portal/templates/skin/webui/component/UIHomePagePortlet/DefaultStylesheet.css" />
<link id="web_BannerPortlet" rel="stylesheet" type="text/css" href= "/web/skin/portal/webui/component/UIBannerPortlet/DefaultStylesheet.css" />
...
</head>

The skin service of GateIn 3.2 manages various types of skins. This service is responsible for discovering and deploying the skins into the portal.

This section consists of the following topics:

Skin configuration

GateIn 3.2 automatically discovers web archives that contain a file descriptor for skins (WEB-INF/gatein-resources.xml). This file is responsible for specifying the portal, portlet and window decorators to be deployed into the skin service.

The full schema can be found in the lib directory:

exo.portal.component.portal.jar/gatein_resources_1_0.xsd

Here is an example where a skin (MySkin) with its CSS location is defined, and a few window decorator skins are specified:


<gatein-resources>
  <portal-skin>
    <skin-name>MySkin</skin-name>
    <css-path>/skin/myskin.css</css-path>
    <overwrite>false</overwrite>
  </portal-skin>
</gatein-resources>

  <!-- window style -->
  <window-style>
    <style-name>MyThemeCategory</style-name>
    <style-theme>
      <theme-name>MyThemeBlue</theme-name>
    </style-theme>
    <style-theme>
      <theme-name>MyThemeRed</theme-name>
    </style-theme>
    ...

Resource Request Filter

Because of the Right-To-Left support, all CSS files need to be retrieved through a Servlet filter and the web application needs to be configured to activate this filter. This is already done for the eXoResources.war web application which contains the default skin.

Any new web applications containing skinning CSS files will need to have the following added to their web.xml :


<filter>
      <filter-name>ResourceRequestFilter</filter-name>
      <filter-class>org.exoplatform.portal.application.ResourceRequestFilter</filter-class>
      </filter>

      <filter-mapping>
      <filter-name>ResourceRequestFilter</filter-name>
      <url-pattern>*.css</url-pattern>
      </filter-mapping>

The default skin for GateIn 3.2 is located as part of the eXoResources.war. The main files associated with the skin are shown below:

(1)WEB-INF/gatein-resources.xml
(2)WEB-INF/web.xml
(3)skin/Stylesheet.css
1

gatein-resources.xml: defines the skin setup to use.

2

web.xml: contains the resource filter and has the display-name set.

3

Stylesheet.css: contains the CSS class definitions for this skin.

gatein-resources.xml

For the default portal skin, this file contains definitions for the portal skin, the window decorations and defines some JavaScript resources which are not related to the skin. The default portal skin does not directly define portlet skins which should be provided by the portlets themeselves.

web.xml

For the default portal skin, the web.xml of eXoResources.war contains a lot of information which is mostly irrelevant to the portal skinning. The areas of interest in this file is the ResourceRequestFilter and the fact that the display-name is set.

Stylesheet.css

This file contains the main stylesheet of the portal skin. The file is the main entry point to the CSS class definitions for the skin. The content of this file is shown below:

Instead of defining all the CSS classes in this file, you can import other CSS stylesheet files, some of which may also import other CSS stylesheets. The CSS classes are split up between multiple files to make it easier for new skins to reuse parts of the default skin.

To reuse the CSS stylesheet from the default portal skin, you need to refer to the default skin from eXoResources. For example, to include the window decorators from the default skin within a new portal skin, you need to use this import: @import url(/eXoResources/skin/Portlet/Stylesheet.css);

A new portal skin needs to be added to the portal through the skin service. The web application which contains the skin will need to be properly configured for the skin service to discover them. This means that ResourceRequestFilter and gatein-resources.xml should be configured properly.

Portal Skin Configuration

The gatein-resources.xml file needs to specify the new portal skin. This includes specifying the name of the new skin, where to locate its CSS stylesheet file and whether to overwrite an existing portal theme with the same name.


<gatein-resources>
  <portal-skin>
    <skin-name>MySkin</skin-name>
    <css-path>/skin/myskin.css</css-path>
    <overwrite>false</overwrite>
  </portal-skin>
</gatein-resources>

The default portal skin and window styles are defined in eXoResources.war/WEB-INF/gatein-resources.xml.

Portal Skin Preview Icon

When selecting a skin, it is possible to preview it. The current skin needs to know about the skin icons for all the available skins; otherwise, it will not be able to show the previews. When creating a new portal, it is recommended to include the preview icons of the other skins and to update the other skins with your new portal skin preview.

The portal skin preview icon is specified through the CSS of the portal skin. To display the preview for the current portal skin, you must specify a specific CSS class and set the icon as the background.

For the portal named MySkin, the CSS class must be defined as follows:

.UIChangeSkinForm .UIItemSelector .TemplateContainer .MySkinImage

In order for the default skin to know about the skin icon for a new portal skin, the preview screenshot needs to be placed in:

01eXoResources.war:/skin/DefaultSkin/portal/webui/component/customization/UIChangeSkinForm/background

The CSS stylesheet for the default portal needs to have the following updated with the preview icon CSS class. For a skin named MySkin, you need to update the following:

01eXoResources.war:/skin/DefaultSkin/portal/webui/component/customization/UIChangeSkinForm/Stylesheet.css
.UIChangeSkinForm .UIItemSelector .TemplateContainer .MySkinImage {
  margin: auto;
  width: 329px; height:204px;
  background: url('background/MySkin.jpg') no-repeat top;
  cursor: pointer ;
}

Window styles are the CSS applied to the window decoration. When the administrator selects a new application to add to a page, he can decide which style of decoration would go around the window if any.

Window Style Configuration

Window Styles are defined within the gatein-resources.xml file which is used by the skin service to deploy the window style into the portal. Window styles can belong in with a window style category, this category and the window styles need to be specified in the resources file.

The following gatein-resource.xml fragment adds MyThemeBlue and MyThemeRed to the MyTheme category.


<window-style>
  <style-name>MyTheme</style-name>
  <style-theme>
    <theme-name>MyThemeBlue</theme-name>
  </style-theme>
  <style-theme>
    <theme-name>MyThemeRed</theme-name>
  </style-theme>
</window-style>

The windows style configuration for the default skin is configured in: 01eXoResources.war/WEB-INF/gatein-resources.xml

Window Style CSS

To display the window decorators for the skin service, it must have the CSS classes with specific naming related to the window style name. The service will try and display the CSS based on this naming. The CSS class must be included as part of the current portal skin for displaying the window decorators.

The location of the window decorator CSS classes for the default portal theme is located at:

01eXoResources.war/skin/PortletThemes/Stylesheet.css

Create the CSS file:


/*---- MyTheme ----*/
.MyTheme .WindowBarCenter .WindowPortletInfo {
  
margin-right: 80px; /* orientation=lt */
  
margin-left: 80px; /* orientation=rt */
}
.MyTheme .WindowBarCenter .ControlIcon {
  
float: right;/* orientation=lt */
  
float: left;/* orientation=rt */
  
width: 24px; 
  
height: 17px;
  
cursor: pointer;
  
background-image: url('background/MyTheme.png');
}
.MyTheme .ArrowDownIcon {
  
background-position: center 20px;
}
.MyTheme .OverArrowDownIcon {
  
background-position: center 116px;
}
.MyTheme .MinimizedIcon {
  
background-position: center 44px;
}
.MyTheme .OverMinimizedIcon {
  
background-position: center 140px;
}
.MyTheme .MaximizedIcon {
  
background-position: center 68px;
}
.MyTheme .OverMaximizedIcon {
  
background-position: center 164px;
}
.MyTheme .RestoreIcon {
  
background-position: center 92px;
}
.MyTheme .OverRestoreIcon {
  
background-position: center 188px;
}
.MyTheme .NormalIcon {
  
background-position: center 92px;
}
.MyTheme .OverNormalIcon {
  
background-position: center 188px;
}
.UIPageDesktop .MyTheme .ResizeArea {
  
float: right;/* orientation=lt */
  
float: left;/* orientation=rt */
  
width: 18px; height: 18px;
  
cursor: nw-resize;
  
background: url('background/ResizeArea18x18.gif') no-repeat left top; /* orientation=lt */
  
background: url('background/ResizeArea18x18-rt.gif') no-repeat right top; /* orientation=rt */
}
.MyTheme .Information {
  
height: 18px; line-height: 18px;
  
vertical-align: middle; font-size: 10px;
  
padding-left: 5px;/* orientation=lt */
  
padding-right: 5px;/* orientation=rt */
  
margin-right: 18px;/* orientation=lt */
  
margin-left: 18px;/* orientation=rt */
}
.MyTheme .WindowBarCenter .WindowPortletIcon {
  
background-position: left top; /* orientation=lt */
  
background-position: right top; /* orientation=rt */
  
padding-left: 20px; /* orientation=lt */
  
padding-right: 20px; /* orientation=rt */
  
height: 16px;
  
line-height: 16px;
}
.MyTheme .WindowBarCenter .PortletName {
  
font-weight: bold;
  
color: #333333;
  
overflow: hidden;
  
white-space: nowrap;
  
width: 100%;
}
.MyTheme .WindowBarLeft {
  
padding-left: 12px;
  
background-image: url('background/MyTheme.png');
  
background-repeat: no-repeat;
  
background-position: left -148px;
}
.MyTheme .WindowBarRight {
  
padding-right: 11px;
  
background-image: url('background/MyTheme.png');
  
background-repeat: no-repeat;
  
background-position: right -119px;
}
.MyTheme .WindowBarCenter {
  
background-image: url('background/MyTheme.png');
  
background-repeat: repeat-x;
  
background-position: left -90px;
}
.MyTheme .WindowBarCenter .FixHeight {
  
height: 21px;
  
padding-top: 8px;
}
.MyTheme .MiddleDecoratorLeft {
  
padding-left: 12px;
  
background: url('background/MyTheme.png') repeat-y left;
}
.MyTheme .MiddleDecoratorRight {
  
padding-right: 11px;
  
background: url('background/MyTheme.png') repeat-y right;
}
.MyTheme .MiddleDecoratorCenter {
  
background: #ffffff;
}
.MyTheme .BottomDecoratorLeft {
  
MyTheme: 12px;
  
background-image: url('background/MyTheme.png');
  
background-repeat: no-repeat;
  
background-position: left -60px;
}
.MyTheme .BottomDecoratorRight {
  
padding-right: 11px;
  
background-image: url('background/MyTheme.png');
  
background-repeat: no-repeat;
  
background-position: right -30px;
}
.MyTheme .BottomDecoratorCenter {
  
background-image: url('background/MyTheme.png');
  
background-repeat: repeat-x;
  
background-position: left top;
}
.MyTheme .BottomDecoratorCenter .FixHeight {
  
height: 30px;
}

Set Default Window Style

To set the default window style to be used for a portal, you need to specify the CSS classes for a theme called DefaultTheme.

Portlets often require additional styles that may not be defined by the portal skin. GateIn 3.2 allows you to define additional stylesheets for each portlet and will append the corresponding link tags to the head.

The link ID will be of the form {portletAppName}{PortletName}. For example: ContentPortlet in 01eXoResources.war/WEB-INF/gatein-resources.xml and content.war in 01eXoResources.war/WEB-INF/gatein-resources.xml will give id="contentContentPortlet".

To define a new CSS file to include whenever a portlet is available on a portal page, the following fragment needs to be added to gatein-resources.xml.


<portlet-skin>
  <application-name>portletAppName</application-name>
  <portlet-name>PortletName</portlet-name>
  <skin-name>Default</skin-name>
  <css-path>/skin/DefaultStylesheet.css</css-path>
</portlet-skin>

<portlet-skin>
  <application-name>portletAppName</application-name>
  <portlet-name>PortletName</portlet-name>
  <skin-name>OtherSkin</skin-name>
  <css-path>/skin/OtherSkinStylesheet.css</css-path>
</portlet-skin>

This will load the DefaultStylesheet.css or OtherSkinStylesheet.css when the Default skin or OtherSkin is used respectively.

Change portlet icons

Each portlet can be represented by a unique icon that you can see in the portlet registry or page editor. This icon can be changed by adding an image to the directory of the portlet webapplication:

To use the icon correctly, it must be named after the portlet.

For example, the icon for an account portlet named AccountPortlet would be located at:

Easier CSS debugging

By default, CSS files are cached and their imports are merged into a single CSS file at the server side. This reduces the number of HTTP requests from the browser to the server.

The optimization code is quite simple as all the CSS files are parsed at the server startup time and all the @import and url(...) references are rewritten to support a single flat file. The result is stored in a cache directly used from the ResourceRequestFilter.

Although the optimization is useful for production environments, it may be easier to deactivate this optimization while debugging stylesheets. To do so, set the java system property exo.product.developing to true.

For example, the property can be passed as a JVM parameter with the -D option when running GateIn.

sh $PLATFORM_JBOSS_HOME/bin/run.sh -Dexo.product.developing=true

Warning

This option may cause display bugs with certain browsers, such as Internet Explorer.

Some CSS techniques

It is recommended that you have some experiences with CSS before studying GateIn 3.2 CSS.

GateIn 3.2 relies heavily on CSS to create the layout and effects for the UI. Some common techniques for customizing GateIn 3.2 CSS are explained below.

This section describes the portal lifecycle from the application server start to its stop and how requests are handled.

Application Server start and stop

A portal instance is simply a web application deployed as a WAR in an application server. Portlets are also part of an enhanced WAR called a portlet application.

GateIn 3.2 does not require any particular setup for your portlet in most common scenarios and the web.xml file can remain without any GateIn 3.2 specific configuration.

During deployment, GateIn 3.2 will automatically and transparently inject a servlet into the portlet application to be able to interact with it. This feature is dependent on the underlying servlet container but will work out of the box on the proposed bundles.

Command Servlet

The servlet is the main entry point for incoming requests, it also includes some init codes when the portal is launched. This servlet (org.gatein.wci.command.CommandServlet) is automatically added during deployment and mapped to /tomcatgateinservlet.

This is equivalent to adding the following to web.xml.


<servlet>
  <servlet-name>TomcatGateInServlet</servlet-name>
  <servlet-class>org.gatein.wci.command.CommandServlet</servlet-class>
  <load-on-startup>0</load-on-startup>
</servlet>
  
<servlet-mapping>
  <servlet-name>TomcatGateInServlet</servlet-name>
  <url-pattern>/tomcatgateinservlet</url-pattern>
</servlet-mapping>

It is possible to filter on the CommandServlet by filtering the URL pattern used by the Servlet mapping.

The example below would create a servlet filter that calculates the time of execution of a portlet request.

The filter class:

package org.example;


import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class MyFilter implements javax.servlet.Filter {
  public void doFilter(ServletRequest request, ServletResponse response,
      FilterChain chain) throws IOException, ServletException
  {
    long beforeTime = System.currentTimeMillis();
    chain.doFilter(request, response);
    long afterTime = System.currentTimeMillis();
    System.out.println("Time to execute the portlet request (in ms): " + (afterTime - beforeTime));
  }
  public void init(FilterConfig config) throws ServletException
  {
  }
  public void destroy()
  {
  }
}

The Java EE web application configuration file (web.xml) of the portlet on which we want to know the time to serve a portlet request. As mentioned above, GateIn 3.2 does not require anything special to be included, only the URL pattern to set has to be known.


<?xml version="1.0"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
    version="2.5">
        
  <filter>
    <filter-name>MyFilter</filter-name>
    <filter-class>org.example.MyFilter</filter-class>        
  </filter>

  <filter-mapping>
    <filter-name>MyFilter</filter-name>
    <url-pattern>/tomcatgateinservlet</url-pattern>
    <dispatcher>INCLUDE</dispatcher>  
  </filter-mapping>    
    
</web-app>

See also

GateIn 3.2 default homepage URL is http://{hostname}:{port}/portal/. There may be multiple independent portals deployed in parallel at any given time, each of which has its root context (i.e.: http://{hostname}:{port}/sample-portal/). Each portal is internally composed of one or more 'portals'. It is required to have at least one such portal - the default one is called 'classic'. When accessing the default homepage URL of GateIn 3.2, you are automatically redirected to the 'classic' portal. The default portal performs another important task. When starting up GateIn 3.2 for the first time, its JCR database will be empty (that's where portals keep their runtime-configurable settings). It is the default portal used to detect this, and to trigger automatic data initialization.

Configuration

The following example configuration can be found at: "portal.war:/WEB-INF/conf/portal/portal-configuration.xml".


<component>
    <key>org.exoplatform.portal.config.UserPortalConfigService</key>
    <type>org.exoplatform.portal.config.UserPortalConfigService</type>
    <component-plugins>           
     <component-plugin>
       <name>new.portal.config.user.listener</name>
       <set-method>initListener</set-method>
       <type>org.exoplatform.portal.config.NewPortalConfigListener</type>
       <description>this listener init the portal configuration</description>
       <init-params>
         <value-param>
           <name>default.portal</name>
           <description>The default portal for checking db is empty or not</description>
           <value>classic</value>
         </value-param> 
         ...
       </init-params>
     </component-plugin>
    </component-plugins> 
  </component>

In this example, the classic portal has been set as the default.

Delete Portals Definition by Configuration

In some cases, some portal definitions are defined but not used any more. If you want to delete them, you can add some configurations to portal.war/WEB-INF/conf/portal/portal-configuration.xml.

To delete a portal definition or a portal template definition, you need to define a component plug-in as the example below:


<external-component-plugins>
    <target-component>org.exoplatform.portal.config.UserPortalConfigService</target-component>
    <component-plugin>
      <name>new.portal.config.user.listener</name>
      <set-method>deleteListenerElements</set-method>
      <type>org.exoplatform.portal.config.NewPortalConfigListener</type>
      <description>this listener delete some predefined portal and templates configuration</description>
      <init-params>
        <object-param>
          <name>site.templates.location</name>
          <description>description</description>
          <object type="org.exoplatform.portal.config.SiteConfigTemplates">
            <field name="portalTemplates">
              <collection type="java.util.HashSet">
                <value>
                  <string>basic</string>
                </value>
                <value>
                  <string>classic</string>
                </value>
              </collection>
            </field>
          </object>
        </object-param>
        <object-param>
          <name>portal.configuration</name>
          <description>description</description>
          <object type="org.exoplatform.portal.config.NewPortalConfig">
            <field  name="predefinedOwner">
              <collection type="java.util.HashSet">
                <value><string>classic</string></value>
              </collection>
            </field>
            <field name="ownerType"><string>portal</string></field>
          </object>
        </object-param>
      </init-params>
    </component-plugin>
</external-component-plugins>

Set the info bar shown by default for portlet

You can set the info bar shown by default for portlets of a portal by adding a property for the portal-config configuration in the portal.xml file.


<properties>
    <entry key="showPortletInfo">1</entry>
</properties>

There are two values for "showPortletInfo": 0 and 1. If the value is 1, the info bar of portlets is shown by default. If the value is 0, it is not.

See also

The default permission configuration for the portal is defined through org.exoplatform.portal.config.UserACL component configuration in the file portal.war:/WEB-INF/conf/portal/portal-configuration.xml.

It defines 8 permissions types:


<component>
  <key>org.exoplatform.portal.config.UserACL</key>
  <type>org.exoplatform.portal.config.UserACL</type>
  <init-params>
    <value-param>
      <name>super.user</name>
      <description>administrator</description>
      <value>root</value>
    </value-param>

    <value-param>
      <name>portal.creator.groups</name>
      <description>groups with membership type have permission to manage portal</description>
      <value>*:/platform/administrators,*:/organization/management/executive-board</value>
    </value-param>

    <value-param>
      <name>navigation.creator.membership.type</name>
      <description>specific membership type have full permission with group navigation</description>
      <value>manager</value>
    </value-param>
    <value-param>
      <name>guests.group</name>
      <description>guests group</description>
      <value>/platform/guests</value>
    </value-param>
    <value-param>
      <name>access.control.workspace</name>
      <description>groups with memberships that have the right to access the User Control Workspace</description>
      <value>*:/platform/administrators,*:/organization/management/executive-board</value>
    </value-param>
  </init-params>
</component>

Overwrite Portal Default Permissions

When creating the custom portals and portal extensions, it is possible to override the default configuration by using org.exoplatform.portal.config.PortalACLPlugin, configuring it as an external-plugin of org.exoplatform.portal.config.UserACL service:


<external-component-plugins>
    <target-component>org.exoplatform.portal.config.UserACL</target-component>
    <component-plugin>
      <name>addPortalACLPlugin</name>
      <set-method>addPortalACLPlugin</set-method>
      <type>org.exoplatform.portal.config.PortalACLPlugin</type>
      <description>setting some permission for portal</description>
      <init-params>
        <values-param>
          <name>access.control.workspace.roles</name>
          <value>*:/platform/administrators</value>
          <value>*:/organization/management/executive-board</value>
        </values-param>
        <values-param>
          <name>portal.creation.roles</name>
          <value>*:/platform/administrators</value>
          <value>*:/organization/management/executive-board</value>
        </values-param>
      </init-params>
    </component-plugin>
  </external-component-plugins>

See also

There are 3 navigation types available to portal users, including Portal Navigation, Group Navigation, and User Navigation. These navigations are configured using the standard XML syntax in the file: "portal.war:/WEB-INF/conf/portal/portal-configuration.xml".


<component>
   <key>org.exoplatform.portal.config.UserPortalConfigService</key>
   <type>org.exoplatform.portal.config.UserPortalConfigService</type>
   <component-plugins>
      <component-plugin>
         <name>new.portal.config.user.listener</name>
         <set-method>initListener</set-method>
         <type>org.exoplatform.portal.config.NewPortalConfigListener
      </type>
         <description>this listener init the portal configuration
      </description>
         <init-params>
            <value-param>
               <name>default.portal</name>
               <description>The default portal for checking db is empty or not</description>
               <value>classic</value>
            </value-param>
            <value-param>
               <name>page.templates.location</name>
               <description>the path to the location that contains Page templates</description>
               <value>war:/conf/portal/template/pages</value>
            </value-param>
            <value-param>
               <name>override</name>
               <description>The flag parameter to decide if portal metadata is overriden on restarting server
            </description>
               <value>false</value>
            </value-param>
            <object-param>
               <name>site.templates.location</name>
               <description>description</description>
               <object type="org.exoplatform.portal.config.SiteConfigTemplates">
                  <field name="location">
                     <string>war:/conf/portal</string>
                  </field>
                  <field name="portalTemplates">
                     <collection type="java.util.HashSet">
                        <value><string>basic</string></value>
                        <value><string>classic</string></value>
                     </collection>
                  </field>
                  <field name="groupTemplates">
                     <collection type="java.util.HashSet">
                        <value><string>group</string></value>
                     </collection>
                  </field>
                  <field name="userTemplates">
                     <collection type="java.util.HashSet">
                        <value><string>user</string></value>
                     </collection>
                  </field>
               </object>
            </object-param>
            <object-param>
               <name>portal.configuration</name>
               <description>description</description>
               <object type="org.exoplatform.portal.config.NewPortalConfig">
                  <field name="predefinedOwner">
                     <collection type="java.util.HashSet">
                        <value><string>classic</string></value>
                     </collection>
                  </field>
                  <field name="ownerType">
                     <string>portal</string>
                  </field>
                  <field name="templateLocation">
                     <string>war:/conf/portal/</string>
                  </field>
                  <field name="importMode">
                     <string>conserve</string>
                  </field>
               </object>
            </object-param>
            <object-param>
               <name>group.configuration</name>
               <description>description</description>
               <object type="org.exoplatform.portal.config.NewPortalConfig">
                  <field name="predefinedOwner">
                     <collection type="java.util.HashSet">
                        <value><string>/platform/administrators</string></value>
                        <value><string>/platform/users</string></value>
                        <value><string>/platform/guests</string></value>
                        <value><string>/organization/management/executive-board</string></value>
                     </collection>
                  </field>
                  <field name="ownerType">
                     <string>group</string>
                  </field>
                  <field name="templateLocation">
                     <string>war:/conf/portal</string>
                  </field>
                  <field name="importMode">
                     <string>conserve</string>
                  </field>
               </object>
            </object-param>
            <object-param>
               <name>user.configuration</name>
               <description>description</description>
               <object type="org.exoplatform.portal.config.NewPortalConfig">
                  <field name="predefinedOwner">
                     <collection type="java.util.HashSet">
                        <value><string>root</string></value>
                        <value><string>john</string></value>
                        <value><string>mary</string></value>
                        <value><string>demo</string></value>
                        <value><string>user</string></value>
                     </collection>
                  </field>
                  <field name="ownerType">
                     <string>user</string>
                  </field>
                  <field name="templateLocation">
                     <string>war:/conf/portal</string>
                  </field>
                  <field name="importMode">
                     <string>conserve</string>
                  </field>
               </object>
            </object-param>
         </init-params>
      </component-plugin>
   </component-plugins>
</component>

This XML configuration defines where in the portal's war to look for configuration, and which portals, groups, and user specific views to include in portal/group/user navigation. Those files will be used to create an initial navigation when the portal is launched in the first time. That information will then be stored in the JCR content repository, and can then be modified and managed from the portal UI.

Each portal, groups and users navigation is indicated by a configuration paragraph, for example:


<object-param>
   <name>portal.configuration</name>
   <description>description</description>
(1)   <object type="org.exoplatform.portal.config.NewPortalConfig">
      <field name="predefinedOwner">
         <collection type="java.util.HashSet">
            <value><string>classic</string></value>
         </collection>
(2)      </field>
      <field name="ownerType">
         <string>portal</string>
(3)      </field>
      <field name="templateLocation">
         <string>war:/conf/portal/</string>
(4)      </field>
      <field name="importMode">
         <string>conserve</string>
      </field>
   </object>
</object-param>
1

predefinedOwner define the navigation owner, portal will look for the configuration files in folder with this name, if there is no suitable folder, a default portal will be created and its name is this value.

2

ownerType define the type of portal navigation. It may be a portal, group or user

3

templateLocation the classpath where contains all portal configuration files

4

importMode The mode for navigation import. There are 4 types of import mode:

  • conserve: Import data when it does not exist, otherwise do nothing.
  • insert: Import data when it does not exist, otherwise performs a strategy that adds new data only.
  • merge: Import data when it does not exist, update data when it exists.
  • overwrite: Overwrite data whatsoever.

Base on these parameters, portal will look for the configuration files and create a relevant portal navigation, pages and data import strategy. The portal configuration files will be stored in folders with path look like {templateLocation}/{ownerType}/{predefinedOwner}, all navigations are defined in the navigation.xml file, pages are defined in pages.xml and portal configuration is defined in {ownerType}.xml. For example, with the above configuration, portal will look for all configuration files from war:/conf/portal/portal/classic path.

The portal navigation incorporates the pages that can be accessed even when the user is not logged in (assuming the applicable permissions allow the public access). For example, several portal navigations are used when a company owns multiple trademarks, and sets up a website for each of them.

The classic portal is configured by four XML files in the portal.war:/WEB-INF/conf/portal/portal/classic directory:

portal.xml

This file describes the layout and portlets that will be shown on all pages. The layout usually contains the banner, footer, menu and breadcrumbs portlets. GateIn 3.2 is extremely configurable as every view element (even the banner and footer) is a portlet.


<portal-config
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://www.gatein.org/xml/ns/gatein_objects_1_0 http://www.gatein.org/xml/ns/gatein_objects_1_0"
   xmlns="http://www.gatein.org/xml/ns/gatein_objects_1_0">
   <portal-name>classic</portal-name>
   <locale>en</locale>
   <access-permissions>Everyone</access-permissions>
   <edit-permission>*:/platform/administrators</edit-permission>
   <properties>
      <entry key="sessionAlive">onDemand</entry>
      <entry key="showPortletInfo">1</entry>
   </properties>

   <portal-layout>
      <portlet-application>
         <portlet>
            <application-ref>web</application-ref>
            <portlet-ref>BannerPortlet</portlet-ref>
            <preferences>
               <preference>
                  <name>template</name>
                  <value>par:/groovy/groovy/webui/component/UIBannerPortlet.gtmpl</value>
                  <read-only>false</read-only>
               </preference>
            </preferences>
         </portlet>
         <access-permissions>Everyone</access-permissions>
         <show-info-bar>false</show-info-bar>
      </portlet-application>

      <portlet-application>
         <portlet>
            <application-ref>web</application-ref>
            <portlet-ref>NavigationPortlet</portlet-ref>
         </portlet>
         <access-permissions>Everyone</access-permissions>
         <show-info-bar>false</show-info-bar>
      </portlet-application>

      <portlet-application>
         <portlet>
            <application-ref>web</application-ref>
            <portlet-ref>BreadcumbsPortlet</portlet-ref>
         </portlet>
         <access-permissions>Everyone</access-permissions>
         <show-info-bar>false</show-info-bar>
      </portlet-application>

      <page-body> </page-body>

      <portlet-application>
         <portlet>
            <application-ref>web</application-ref>
            <portlet-ref>FooterPortlet</portlet-ref>
            <preferences>
               <preference>
                  <name>template</name>
                  <value>par:/groovy/groovy/webui/component/UIFooterPortlet.gtmpl</value>
                  <read-only>false</read-only>
               </preference>
            </preferences>
         </portlet>
         <access-permissions>Everyone</access-permissions>
         <show-info-bar>false</show-info-bar>
      </portlet-application>

   </portal-layout>

</portal-config>

It is also possible to apply a nested container that can also contain portlets. Row, column or tab containers are then responsible for the layout of their child portlets.

Use the page-body tag to define where GateIn 3.2 should render the current page.

The defined classic portal is accessible to "Everyone" (at /portal/public/classic) but only members of the group /platform/administrators can edit it.

navigation.xml

This file defines all the navigation nodes of the portal. The syntax is simple using the nested node tags. Each node refers to a page defined in the pages.xml file (explained next).

If the administrator want to create node labels for each language, they will have to use xml:lang attribute in the label tag with value of xml:lang is the relevant locale.

Otherwise, if they want the node label is localized by resource bundle files, the #{...} syntax will be used, the enclosed property name serves as a key that is automatically passed to the internationalization mechanism. Thus the emphasis property name is replaced by a localized value taken from the associated properties file matching the current locale.

For example:


<node-navigation
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://www.gatein.org/xml/ns/gatein_objects_1_2 http://www.gatein.org/xml/ns/gatein_objects_1_2"
   xmlns="http://www.gatein.org/xml/ns/gatein_objects_1_2">
   <priority>1</priority>
   <page-nodes>
      <node>
         <name>home</name>
         <label xml:lang="en">Home</label>
         <page-reference>portal::classic::homepage</page-reference>
      </node>
      <node>
         <name>sitemap</name>
         <label xml:lang="en">SiteMap</label>
         <visibility>DISPLAYED</visibility>
         <page-reference>portal::classic::sitemap</page-reference>
      </node>
      ..........
   </page-nodes>
</node-navigation>

This navigation tree can have multiple views inside portlets (such as the breadcrumbs portlet) that render the current view node, the site map or the menu portlets.

pages.xml

This configuration file structure is very similar to portal.xml and it can also contain container tags. Each application can decide whether to render the portlet border, the window state, the icons or portlet's mode.


<page-set
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://www.gatein.org/xml/ns/gatein_objects_1_0 http://www.gatein.org/xml/ns/gatein_objects_1_0"
   xmlns="http://www.gatein.org/xml/ns/gatein_objects_1_0">

   <page>
      <name>homepage</name>
      <title>Home Page</title>
      <access-permissions>Everyone</access-permissions>
      <edit-permission>*:/platform/administrators</edit-permission>
      <portlet-application>
         <portlet>
            <application-ref>web</application-ref>
            <portlet-ref>HomePagePortlet</portlet-ref>
            <preferences>
               <preference>
                  <name>template</name>
                  <value>system:/templates/groovy/webui/component/UIHomePagePortlet.gtmpl</value>
                  <read-only>false</read-only>
               </preference>
            </preferences>
         </portlet>
         <title>Home Page portlet</title>
         <access-permissions>Everyone</access-permissions>
         <show-info-bar>false</show-info-bar>
         <show-application-state>false</show-application-state>
         <show-application-mode>false</show-application-mode>
      </portlet-application>
   </page>

   <page>
      <name>sitemap</name>
      <title>Site Map</title>
      <access-permissions>Everyone</access-permissions>
      <edit-permission>*:/platform/administrators</edit-permission>
      <portlet-application>
         <portlet>
            <application-ref>web</application-ref>
            <portlet-ref>SiteMapPortlet</portlet-ref>
         </portlet>
         <title>SiteMap</title>
         <access-permissions>Everyone</access-permissions>
         <show-info-bar>false</show-info-bar>
      </portlet-application>
   </page>
   .......
</page-set>
  • Import Mode

    Information about modes for the import strategy.

  • Data Import Strategy

    Information about 3 types of object data: Portal Config, Page Data and Navigation Data.

In the Portal extension mechanism, developers can define an extension that Portal data can be customized by configurations in the extension. There are several cases which an extension developer wants to define how to customize the Portal data, for example modifying, overwriting or just inserting a bit into the data defined by the portal. Therefore, GateIn also defines several modes for each case and the only thing which a developer has to do is to clarify the usecase and reasonably configure extensions.

This section shows you how data are changes in each mode.

The 'Portal Data' term which has been referred in the previous sections can be classified into three types of object data: Portal Config, Page Data and Navigation Data; each of which has some differences in the import strategy.

Navigation Data

The navigation data import strategy will be processed to the import mode level as the followings:
  • CONSERVE: If the navigation exists, leave it untouched. Otherwise, import data.
  • INSERT: Insert the missing description data, but add only new nodes. Other modifications remains untouched.
  • MERGE: Merge the description data, add missing nodes and update same name nodes.
  • OVERWRITE: Always destroy the previous data and recreate it.

In the GateIn navigation structure, each navigation can be referred to a tree which each node links to a page content. Each node contains some description data, such as label, icon, page reference, and more. Therefore, GateIn provides a way to insert or merge new data to the initiated navigation tree or a sub-tree.

The merge strategy performs the recursive comparison of child nodes between the existing persistent nodes of a navigation and the transient nodes provided by a descriptor:

Let's see the example with two navigation nodes in each import mode. In this case, there are 2 navigation definitions:

<node-navigation>
  <page-nodes>
    <node>
      <name>foo</name>
      <icon>foo_icon_1</icon>
      <node>
        <name>juu</name>
        <icon>juu_icon</icon>
      </node>
    </node>
    <node>
      <name>daa</name>
      <icon>daa_icon</icon>
    </node>
  </page-nodes>
</node-navigation>
Navigation node tree hierarchy

<node-navigation>
  <page-nodes>
    <node>
      <name>foo</name>
      <icon>foo_icon_2</icon>
    </node>
    <node>
      <name>bar</name>
      <icon>bar_icon</icon>
    </node>
  </page-nodes>
</node-navigation>
Navigation node tree hierarchy

For example, the navigation1 is loaded before navigation2. The Navigation Importer processes on two navigation definitions, depending on the Import Mode defined in portal configuration.

  • Case 1: Import mode is CONSERVE.

    With the CONSERVE mode, data are only imported when they do not exist. So, if the navigation has been created by the navigation1 definition, the navigation2 definition does not affect anything on it. We have the result as following

  • Case 2: Import mode is INSERT.

    If a node does not exist, the importer will add new nodes to the navigation tree. You will see the following result:

    Hereafter, the node 'bar' is added to the navigation tree, because it does not exist in the initiated data. Other nodes are kept in the import process.

  • Case 3: Import mode is MERGE.

    The MERGE mode indicates that a new node is added to the navigation tree, and updates the node data (such node label and node icon in the example) if it exists.

  • Case 4: Import mode is OVERWRITE.

    Everything will be destroyed and replaced with new data if the OVERWRITE mode is used.

Portal Config

PortalConfig defines the portal name, permission, layout and some properties of a site. These information are configured in the portal.xml, group.xml or user.xml, depending on the site type. The PortalConfig importer performs a strategy that is based on the mode defined in NewPortalConfigListener, including CONSERVE, INSERT, MERGE or OVERWRITE. Let's see how the import mode affects in the process of portal data performance:

Page Data

The import mode affects the page data import as the same as Portal Config.

See also

Assumed Knowledge

GateIn 3.2 is fully configurable for internationalization; however, users should have a general knowledge of Internationalization in Java products before attempting these configurations.

Sun Java hosts a comprehensive guide to internationalize Java products at http://java.sun.com/docs/books/tutorial/i18n/TOC.html.

All GateIn 3.2 applications contain property files for various languages. They are packaged with the portlets applications in a WEB-INF/classes/locale/ directory.

These files are located in the classes folder of the WEB-INF directory to be loaded by the ClassLoader.

All resource files are in a subfolder named locale.

For example, the translations for the NavigationPortlet are located in web.war/WEB-INF/classes/locale/portlet/portal.

NavigationPortlet_de.properties
NavigationPortlet_en.properties
NavigationPortlet_es.properties
NavigationPortlet_fr.properties
NavigationPortlet_nl.properties
NavigationPortlet_ru.properties
NavigationPortlet_uk.properties
NavigationPortlet_ar.xml

Those files contain typical key=value Java EE properties. For example, the French one:

javax.portlet.title=Portlet Navigation

There are also properties files in the portal itself. They form the portal resource bundle.

From a portlet, you can then access translations from the portlet itself or shared at the portal level, both are aggregated when you need them.

Translation in XML format

It is also possible to use a proprietary XML format to define translations. This is a more convenient way to translate a document for some languages, such as Japanese, Arabic or Russian. Property files have to be ASCII encoded, while the XML file can define its encoding. As a result, it is easier for you to read or edit a translation in XML instead of having to decode and encode the property file.

For more information, refer to Section 2.9, “XML Resources Bundles”.

Various languages are available in the portal package. The configuration below will define which languages shown in the "Change Language" section and made available to users.

The portal.war:/WEB-INF/conf/common/common-configuration.xml file of your installation contains the following section:


<component>
  <key>org.exoplatform.services.resources.LocaleConfigService</key>
  <type>org.exoplatform.services.resources.impl.LocaleConfigServiceImpl</type>
  <init-params>
    <value-param>
      <name>locale.config.file</name>
      <value>war:/conf/common/locales-config.xml</value>
    </value-param>
  </init-params>
</component>

This configuration points to the locale configuration file.

The locale configuration file (portal.war:/WEB-INF/conf/common/locales-config.xml) contains the following code:


<?xml version="1.0" encoding="UTF-8"?>
<locales-config>
(1)  <locale-config>
(2)    <locale>en</locale>
(3)    <output-encoding>UTF-8</output-encoding>
(4)    <input-encoding>UTF-8</input-encoding>
    <description>Default configuration for english locale</description>
  </locale-config>

  <locale-config>
    <locale>fr</locale>
    <output-encoding>UTF-8</output-encoding>
    <input-encoding>UTF-8</input-encoding>
    <description>Default configuration for the french locale</description>
  </locale-config>

  <locale-config>
    <locale>ar</locale>
    <output-encoding>UTF-8</output-encoding>
    <input-encoding>UTF-8</input-encoding>
(5)    <description>Default configuration for the arabic locale</description>
    <orientation>rt</orientation>
  </locale-config>
</locales-config>
1

locale The locale has to be defined, such as http://ftp.ics.uci.edu-pub-ietf-http-related-iso639.txt. In this example, "ar" is Arabic.

2

output-encoding deals with the character encoding. It is recommended that UTF-8 be used.

3

input-encoding In the Java implementation, the encoding parameters will be used for the request response stream. The input-encoding parameter will be used for requesting setCharacterEncoding(..).

4

description Description for the language

5

orientation The default orientation of text and images is Left-To-Right. GateIn 3.2 supports Right-To-Left orientation. Modifying the text orientation is explained in Section 2.8, “RTL (Right To Left) Framework”.

The resource bundle service is configured in: portal.war:/WEB-INF/conf/common/common-configuration.xml:


<component>
  <key>org.exoplatform.services.resources.ResourceBundleService</key>
  <type>org.exoplatform.services.resources.impl.SimpleResourceBundleService</type>
  <init-params>
(1)    <values-param>
      <name>classpath.resources</name>
      <description>The resources  that start with the following package name should be load from file system</description>
      <value>locale.portlet</value>
    </values-param>
(2)    <values-param>
      <name>init.resources</name>
      <description>Initiate the following resources during the first launch</description>
      <value>locale.portal.expression</value>
      <value>locale.portal.services</value>
      <value>locale.portal.webui</value>
      <value>locale.portal.custom</value>
      <value>locale.navigation.portal.classic</value>
      <value>locale.navigation.group.platform.administrators</value>
      <value>locale.navigation.group.platform.users</value>
      <value>locale.navigation.group.platform.guests</value>
      <value>locale.navigation.group.organization.management.executive-board</value>
    </values-param>
(3)    <values-param>
      <name>portal.resource.names</name>
      <description>The properties files of  the portal ,  those file will be merged
        into one ResoruceBundle properties </description>
      <value>locale.portal.expression</value>
      <value>locale.portal.services</value>
      <value>locale.portal.webui</value>
      <value>locale.portal.custom</value>
    </values-param>
  </init-params>
</component>
1

classpath.resources are discussed in the later section.

2

init.resources initiates resources related to portal, group, user resource bundle.

3

portal.resource.names defines all resources that belong to the Portal Resource Bundle.

These resources are merged into a single resource bundle which is accessible from anywhere in GateIn 3.2. All these keys are located in the same bundle, which is separated from the navigation resource bundles.

Portlets are independent applications and deliver their own resource files.

All shipped portlet resources are located in the locale/portlet subfolder. The ResourceBundleService parameter classpath.resources defines this subfolder.

See the portlet specification for more details about the portlet internationalization.

Standard portlet resource keys

The portlet specifications define three standard keys: Title, Short Title and Keywords. Keywords are formatted as a comma-separated list of tags.

 javax.portlet.title=Breadcrumbs Portlet
 javax.portlet.short-title=Breadcrumbs
 javax.portlet.keywords=Breadcrumbs, Breadcrumb

Debugging resource bundle usage

When translating an application, it can sometimes be difficult to find the right key for a given property.

Execute the portal in the debug mode and select the special language from the available languages,; Magic locale.

This feature translates a key to the same key value.

For example, the translated value for the key "organization.title" is simply the value "organization.title". Selecting that language allows use of the portal and its applications with all the keys visible. This makes it easier to find out the correct key for a given label in the portal page.

See also

The text orientation depends on the current locale setting. The orientation is a Java 5 enum that provides a set of functionalities:

LT, // Western Europe
   RT, // Middle East (Arabic, Hebrew)
   TL, // Japanese, Chinese, Korean
   TR; // Mongolian
   public boolean isLT() { ... }
   public boolean isRT() { ... }
   public boolean isTL() { ... }
   public boolean isTR() { ... }

The object defining the Orientation for the current request is the UIPortalApplication. However, it should be accessed at runtime using the RequestContext that delegates to the UIPortalApplication.

In case of PortalRequestContext, it directly delegates as the PortalRequestContext has a reference to the current UIPortalApplication.

In case of a different context, such as the PortletRequestContext, it delegates to the parent context given the fact that the root RequestContext is always a PortalRequestContext.

Groovy templates

Orientation is defined by implicit variables in the Groovy binding context:

Stylesheet

The skin service handles stylesheet rewriting to accommodate the orientation. It works by appending -lt or -rt to the stylesheet name.

For instance: /web/skin/portal/webui/component/UIFooterPortlet/DefaultStylesheet-rt.css will return the same stylesheet as /web/skin/portal/webui/component/UIFooterPortlet/DefaultStylesheet.css but processed for the RT orientation. The -lt suffix is optional.

Stylesheet authors can annotate their stylesheet to create content that depends on the orientation.



Images

Sometimes, it is necessary to create the RT version of an image that will be used from a template or from a stylesheet. However, symmetric images can be automatically generated avoiding the necessity to create a mirrored version of an image and furthermore avoiding maintenance cost.

The web resource filter uses the same naming pattern as the skin service. When an image ends with the -rt suffix, the portal will attempt to locate the original image and create a mirror of it.

For instance: requesting the image /GateInResources/skin/DefaultSkin/webui/component/UITabSystem/UITabs/background/NormalTabStyle-rt.gif returns a mirror of the image /GateInResources/skin/DefaultSkin/webui/component/UITabSystem/UITabs/background/NormalTabStyle.gif.

Here is an example combining stylesheet and images:


line-height: 24px;
background: url('background/NavigationTab.gif') no-repeat right top; /* orientation=lt */
background: url('background/NavigationTab-rt.gif') no-repeat left top; /* orientation=rt */
padding-right: 2px; /* orientation=lt */
padding-left: 2px; /* orientation=rt */

Client side JavaScript

The eXo.core.I18n object provides the following parameters for orientation:

See also

Motivation

Resource bundles are usually stored in property files. However, as property files are plain files, issues with the encoding of the file may arise. The XML resource bundle format has been developed to provide an alternative to property files.

XML format

The XML format is very simple and has been developed based on the DRY (Don't Repeat Yourself) principle. The resource bundle keys are hierarchically defined and we can leverage the hierarchic nature of the XML for that purpose. Here is an example of turning a property file into an XML resource bundle file:

UIAccountForm.tab.label.AccountInputSet = ...
UIAccountForm.tab.label.UIUserProfileInputSet = ...
UIAccountForm.label.Profile = ...
UIAccountForm.label.HomeInfo= ...
UIAccountForm.label.BusinessInfo= ...
UIAccountForm.label.password= ...
UIAccountForm.label.Confirmpassword= ...
UIAccountForm.label.email= ...
UIAccountForm.action.Reset= ...

<?xml version="1.0" encoding="UTF-8"?>
<bundle>
  <UIAccountForm>
    <tab>
      <label>
        <AccountInputSet>...</AccountInputSet>
        <UIUserProfileInputSet>...</UIUserProfileInputSet>
      </label>
    </tab>
    <label>
      <Profile>...</Profile>
      <HomeInfo>...</HomeInfo>
      <BusinessInfo>...</BusinessInfo>
      <password>...</password>
      <Confirmpassword>...</Confirmpassword>
      <email>...</email>
    </label>
    <action>
      <Reset>...</Reset>
    </action>
  </UIAccountForm>
</bundle>

Portal support

To be loaded by the portal at runtime (actually the resource bundle service), the name of the file must be the same as a property file and it must use the .xml suffix.

For example, for the Account Portlet to be displayed in Arabic, the resource bundle would be AccountPortlet_ar.xml rather than AccountPortlet_ar.properties.

See also

In this section, you will learn how to configure the Upload service that is defined by the org.exoplatform.upload.UploadService class.

This can be configured with the following XML code:


<component>
   <type>org.exoplatform.upload.UploadService</type>
     <init-params>
       <value-param>
        <name>upload.limit.size</name>
        <description>Maximum size of the file to upload in MB</description>
        <value>10</value>
      </value-param>
    </init-params>  
  </component>

This code allows uploading files with the default size limit (10MB). The default value unit is in Megabytes.

This limit will be used by default by all applications if no application-specific limit is set. Setting a different limit for applications is discussed in a later section.

If the value is set to 0, the upload size is unlimited.

Procedure 2.2. How to use the upload component

  1. Create an org.exoplatform.webui.form.input.UIUploadInput object type by using one of three following constructors:

    • This is the default constructor that allows uploading the file with the size of 10 MB.

      public UIUploadInput(String name, String bindingExpression, int limitFile) 
    • This constructor allows you to customize the size limit of uploaded files by using the limitSize parameter. The default value unit is Megabytes.

      public UIUploadInput(String name, String bindingExpression,int limitFile, int limitSize)
    • This constructor allows you to customize the size limit and the value unit by using the limitSize and unit parameters respectively.

      In GateIn, you can set the value unit to Megabytes (MB), Kilobytes (KB) or Gigabytes (GB).

      public UIUploadInput(String name, String bindingExpression, int limitFile, int limitSize, UploadUnit unit)

    The following is an example using the third form:

    PortletRequestContext pcontext = (PortletRequestContext)WebuiRequestContext.getCurrentInstance();
    
    PortletPreferences portletPref = pcontext.getRequest().getPreferences();
    int limitFile = Integer.parseInt(portletPref.getValue("uploadFileLimit", "1").trim());
    int limitSize = Integer.parseInt(portletPref.getValue("uploadFileSizeLimit", "").trim());
    UploadUnit limitUnit = UploadUnit.valueOf(portletPref.getValue("uploadFileLimitUnit", "MB").trim());
    UIUploadInput uiInput = new UIUploadInput("upload", "upload", limitFile, limitSize, limitUnit);
  2. To obtain the limit from the XML configuration, add the following code to the either portlet.xml or portlet-preferences.xml:

    
    <The number of files are uploaded -->
        <preference>
            <name>uploadFileLimit</name>
            <value>3</value>
            <read-only>false</read-only>
        </preference>
    <The size limit -->
        <preference>
            <name>uploadFileSizeLimit</name>
            <value>300</value>
            <read-only>false</read-only>
        </preference>
    <The unit limit -->
        <preference>
            <name>uploadFileLimitUnit</name>
            <value>KB</value>
            <read-only>false</read-only>
        </preference> 

    Note that the 0 value means unlimited upload size, and the value unit is set to MegaBytes.

  3. Use the getUploadDataAsStream() method to get the uploaded data:

    UIUploadInput input = (UIUploadInput)uiForm.getUIInput("upload");
    
    InputStream[] inputStreams = input.getUploadDataAsStreams();
    ...
  4. The upload service stores a temporary file on the file system during the upload process. When the upload is finished, the service must be cleaned to:

    • Delete the temporary file.

    • Delete the classes used for the upload.

    Use the removeUploadResource(String uploadId) method defined in the upload service to purge the file:

    UploadService uploadService = uiForm.getApplicationComponent(UploadService.class) ;
    
    UIUploadInput uiChild = uiForm.getChild(UIFormUploadInput.class) ;
        for(String uploadId : uiChild.getUploadIds())
        {
        uploadService.removeUpload(uploadId) ;
        }

    Saving the uploaded file

    Ensure the file is saved before the service is cleaned.

Purpose

The loading mask layer is deployed after an ajax-call. It aims at blocking the GUI to prevent further user actions until the the ajax-request has been completed.

However, the mask layer may need to be deactivated in instances where the portal requires user instructions before the previous instructions have been carried out.

The GUI will be blocked to ensure that the user can only request one action at one time and while the request seems to be synchronous, all ajax requests are always asynchronous. For further information, refer to Section 2.11, “Deactivation of the Ajax Loading Mask Layer”.

Synchronous issue

Most web browsers support ajax requests in two modes: Synchronous and Asynchronous. This mode is specified with a boolean bAsync parameter.

var bAsync = false; // Synchronous
request.open(instance.method, instance.url, bAsync);

However, to work with browsers that do not support the Synchronous requests, bAsync is always set to true (Ajax request will always be asynchronous).

// Asynchronous request
request.open(instance.method, instance.url, true);

Managing JavaScript in an application like GateIn 3.2 is a critical part of the configuration work. Configuring the scripts correctly will result in the faster response time from the portal.

Every portlet can have its own JavaScript code but in many cases, it is more convenient to reuse some existing shared libraries. For that reason, GateIn 3.2 has a mechanism to easily register the libraries that will be loaded when every page is rendered.

To do so, every WAR deployed in GateIn 3.2 can register the .js files with the gatein-resources.xml configuration file.

The example code snippet below is found in the gatein-resources.xml in the eXoResources.war file.


<javascript>
  <param>
    <js-module>eXo</js-module>
    <js-path>/javascript/eXo.js</js-path>
    <js-priority>0</js-priority>
  </param>
</javascript>

<!-- CORE Javascripts -->
<javascript>
  <param>
    <js-module>eXo.core.Utils</js-module>
    <js-path>/javascript/eXo/core/Util.js</js-path>
    <js-priority>1</js-priority>
  </param>
  <param>
    <js-module>eXo.core.DOMUtil</js-module>
    <js-path>/javascript/eXo/core/DOMUtil.js</js-path>
    <js-priority>1</js-priority>
  </param>
  <param>
    <js-module>eXo.core.Browser</js-module>
    <js-path>/javascript/eXo/core/Browser.js</js-path>
    <js-priority>2</js-priority>
  </param>
  <param>
    <js-module>eXo.core.MouseEventManager</js-module>
    <js-path>/javascript/eXo/core/MouseEventManager.js</js-path>
  </param>
  <param>
    <js-module>eXo.core.UIMaskLayer</js-module>
    <js-path>/javascript/eXo/core/UIMaskLayer.js</js-path>
  </param>
  <param>
    <js-module>eXo.core.Skin</js-module>
    <js-path>/javascript/eXo/core/Skin.js</js-path>
  </param>
  <param>
    <js-module>eXo.core.DragDrop</js-module>
    <js-path>/javascript/eXo/core/DragDrop.js</js-path>
  </param>
  <param>
    <js-module>eXo.core.DragDrop2</js-module>
    <js-path>/javascript/eXo/core/DragDrop2.js</js-path>
  </param>
</javascript>

Note that registered JavaScript files will be merged into a single merged.js file when the server loads. This reduces the number of HTTP calls as shown in the homepage source code:


<script type="text/javascript" src="/portal/javascript/merged.js"></script>

Although this optimization is useful for a production environment, it may be easier to deactivate this optimization while debugging JavaScript problems.

To do this, set the Java system property exo.product.developing to true. GateIn provides two startup scripts that define this property in gatein-dev.sh (for Linux, Mac) and gatein-dev.bat (for Windows).

To generate the merged.js file, set this property to false. If the property is not set, the default value is false.

The property can be passed as a JVM parameter with the -D option in your gatein.sh or gatein.bat startup script.

Every JavaScript file is associated with a module name which acts as a namespace.

Inside the associated JavaScript files, the eXo JavaScript objects are exposed as global variables named after the module.

For example:

eXo.core.DragDrop = new DragDrop();

It is also possible to use the eXo.require() method to lazy load and evaluate some JavaScript codes. This is quite useful for the portlet or gadget applications that will use this JavaScript only once. Otherwise, if the library is reusable in several places, it is better to define it in the gatein-resources.xml file.

The navigation controller is a major enhancement of GateIn that has several goals:

  • Provide non-ambiguous URLs for resources managed by the portal, such as navigation. Previously, different resources were possible for a single URL, even worse, the set of resources available for an URL depends on private navigations (groups and dashboard).

  • Decouple the HTTP request from the portal request. Previously, both were tightly coupled, for instance, the URL for a site had to begin with /public/{sitename} or /private/{sitename} .The navigation controller provides a flexible and configurable mapping.

  • Provide a more friendly URL and let portal administrator configure how the HTTP request should look like.

The WebAppController is the component of GateIn that processes HTTP invocations and transforms them into a portal request. It has been improved with the addition of a request mapping engine (controller) whose role is to make the HTTP request decouple and create a portal request. The mapping engine makes two essential tasks:

The goal of the controller (mapping engine) is to decouple the request processed by GateIn from the incoming HTTP request. Indeed, a request contains data that determine how the request will be processed and such data can be encoded in various places in the request, such as the request path, or a query parameter. The controller allows GateIn to route a request according to a set of parameters (a map) instead of the servlet request.

The controller configuration is declarative in an .xml file named controller.xml, allowing easy reconfiguration of the routing table and it is processed into an internal data structure that is used to perform resolution (routing or rendering).

The controller data cannot be modified by using the portlet interface, but can be still changed at runtime by modifying in the controller.xml file, then calling the WebAppController.reloadConfiguration() method.

The controller configuration that contains the routing rules is loaded from the controller.xml file retrieved in the GateIn configuration directory. Its location is determined by the gatein.controller.config property.

WebAppController loads and initializes the mapping engine.

GateIn's extension project can define their own routing table, thanks to the extension mechanism.

The controller.xml file can be changed and reloaded at runtime. This helps the test of different configurations easily (configuration loading operations) and provides more insight into the routing engine (the findRoutes operation). See Rebuiding controller below for more details.

The WebAppController is annotated with @Managed annotations and is bound under the view=portal,service=controller JMX name and under the "portalcontroller" REST name.

It provides the following attributes and operations:

Most of the controller configuration cares about defining rules (Routing table - contains routes object) that will drive the resolution. Routes are processed during the controller initialization to give a tree of node.

A parameter is defined by a qualified name and there are three kinds of parameters explained in the sections below.

Path parameters allow to associate a portion of the request path with a parameter. Such parameter will match any non empty portions of text except the / character (that is the [^/]+ regular expression) otherwise they can be associated with a regular expression for matching specific patterns. Path parameters are mandatory for matching since they are a part of the request path, however it is allowed to write regular expression matching an empty value.

Encoding

Path parameters may contain the '/' character which is a reserved char for the URI path. This case is specially handled by the navigation controller by using a special character to replace the '/' literals. By default, the character is the colon ":" and can be changed to other possible values (see controller XML schema for possible values) to give a greater amount of flexibility.

This encoding is applied only when the encoding is performed for parameters having a mode set to the default-form value, for instance, it does not happen for navigation node URI (for which / are encoded literally). The separator escape char can still be used but under it is percent escaped form, so by default, a path parameter value containing the colon ":" would be encoded as %3A and conversely the %3A value will be decoded as the colon ":".

Example: No pattern is define, the default one [^/]+ will be used:

As a result of the example above, routing and rendering is as below:

If the request path contains another "/" char, it will not work. The default encoding mode is default-form. In the example above, "/foo/bar" is not matched, so the system returns an empty parameter map.

However, this problem could be solved with the following configuration:

GateIn defines a set of parameters in its routing table, for each client request, the mapping engine processes the request path and return the defined parameters with their values as a Map<QualifiedName, String>

gtn:handler

The gtn:handler names is one of the most important qualified name as it determines which handler will take care of the request processing just after the controller has determined the parameter map. The handler value is used to make a lookup in the handler map of the controller. An handler is a class that extends the WebRequestHandler class and implements the execute(ControllerContext) method. Several handlers are available by default:

gtn:sitetype / gtn:sitename / gtn:path

Those qualified names drives a request for the portal handler. They are used to determine which site to show and which path to resolve against a navigation. For instance, the (gtn:sitetype=portal,gtn:sitename=classic,gtn:path=home) instruct the portal handler to show the home page of the classic portal site.

gtn:lang

This parameter shows which language used in the URL for the portal handler. This is a new feature offered, now language can be specified on URL. It means that users can bookmark that URL (with the information about language) or he can changed the language simply by modifying the URL address.

gtn:componentid / gtn:action / gtn:objectid

The webui parameters used by the portal handler for managing webui component URLs for portal applications (but not for portlet applications).

The controller is designed to render a Map<QualifiedName, String> as an HTTP URL according to its routing table, but to integrate it for easy usage in WebUI Framework of GateIn, you need some more components:

PortalURL

PortalURL plays a similar role at the portal level. Its main role is to abstract the creation of an URL for a resource managed by the portal.

The PortalURL declaration may seem a bit strange at first sight with two generic types: U and R.

A portal URL has various methods but certainly the most important method is the toString() method that generates an URL targeting to the resource. The remaining methods are getter and setter used to mutate the URL configuration, those options will affect the URL representation when it is generated.

Obtaining a PortalURL

PortalURL objects are obtained from RequestContext instance, such as the PortalRequestContext, or the PortletRequestContext. Usually, those are obtained thanks to the getCurrentInstance method of the RequestContext class:

PortalURL are created via to the createURL method that takes an input as a resource type. The resource type is usually a constant and type-safe object that allows to retrieve the PortalURL subclasses:

In reality, you will use a concrete type constant and have instead more concrete code like:

NodeURL

The NodeURL class is one of the subclass of PortalURL that is specialized in navigation node resources:

The NodeURL class does not carry any generic types of its super class, which means that a NodeURL is type-safe and you do not have to worry about generic types.

Using a NodeURL is pretty straightforward:

The NodeURL subclass contains the specialized setter methods to make its usage even easier:

ComponentURL

The ComponentURL subclass is another specialization of PortalURL that allows the creation of WebUI components URLs. ComponentURL is commonly used to trigger WebUI events from client side:

Normally, you should not have to deal with it as the WebUI framework has already an abstraction for managing URL known as URLBuilder. The URLBuilder implementation delegates URL creation to ComponentURL objects.

Portlet URLs

Portlet URLs API implementation delegates to the portal ComponentURL (via the portlet container SPI). It is possible to control the language in the URL from a PortletURL object by setting the gtn:lang property:

Webui URLBuilder

This internal API used to create URL works as usual and delegates to the PortletURL API when the framework is executed in a portlet, and delegates to a ComponentURL API when the framework is executed in the portal context. The API has been modified to take in account the language in URL with two properties on the builder:

Groovy Templates

In a Groovy template, the mechanism to create an URL is the same as the way of APIs above, however a splash of integration has been done to make creation of NodeURL simpler. A closure is bound under the nodeurl name and is available for invocation anytime. It will simply create a NodeURL object and return it:

The nodeurl closure is bound to Groovy template in WebuiBindingContext.

The navigation controller implies a migration of the client code that is coupled to several internal APIs of GateIn. The major impact is related to anything dealing with URL:

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