JBoss.orgCommunity Documentation

Chapter 5. Development

5.1. Portal Lifecycle
5.1.1. Overview
5.1.2. Application Server start and stop
5.1.3. The Command Servlet
5.2. RTL (Right To Left) Framework
5.2.1. Overview
5.2.2. Direction
5.2.3. Groovy templates
5.2.4. Stylesheet
5.2.5. Images
5.2.6. Client side JavaScript
5.3. Internationalization Configuration
5.3.1. Overview
5.3.2. Locales configuration
5.3.3. ResourceBundleService
5.3.4. Navigation Resource Bundles
5.3.5. Portlets
5.4. XML Resources Bundles
5.4.1. Motivation
5.4.2. Portal support
5.4.3. XML format
5.5. Dynamic Layouts
5.5.1. Overview
5.5.2. Advanced Drag and Drop mechanism
5.5.3. Summary
5.6. JavaScript Inter Application Communication
5.6.1. Overview
5.6.2. /eXo
5.6.3. /eXo/portal/notification
5.6.4. Library
5.6.5. Syntax
5.6.6. Example
5.7. Upload Component
5.7.1. Overview
5.7.2. Upload Service
5.7.3. How to use the upload component in your application
5.8. Deactivation of the Ajax Loading Mask Layer
5.8.1. Overview
5.8.2. Purpose of requirement
5.8.3. How to deactivate ajax-loading mask in your code
5.8.4. Synchronous issue
5.9. Accessing User Profile

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

In other words, this is equivalent to adding the following into web.xml (But this is for information only, the servlet is already configured)



<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>

With this in mind it's possible to filter on the CommandServlet by filtering on the URL pattern used by the Servlet mapping. As an example below we will 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 nothing specific to GateIn needs 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>

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. Obviously the -lt suffix is optional.

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

All aspects of internationalization in GateIn products are covered. You should have a general knowledge of Internationalization in Java products. Sun created a good internationalization tutorial .

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

You should notice that

  • the files are located in the classes folder of your WEB-INF, this way they are loaded by the ClassLoader.

  • all resource files are in a subfolder named locale

For instance you will find the translations for the NavigationPortlet 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

Inside those file we find typical key=value Java EE properties. For example the French one:

javax.portlet.title=Portlet Navigation

Furthermore there are properties files in the portal itself. They form together 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 te be ASCII encoded, while the XML file can define its encoding. As a result it's easier for a human being to read (and fix) a translation in XML instead of having to decode and encode the property file.

More information are available here: Section 5.4, “XML Resources Bundles”

Various languages are available in the shipped portal, one may want to add or remove languages. This configuration will define the list of languages in the "Change Language" section of the portal that the user can pick from.

In the 02portal.war:/WEB-INF/conf/common/common-configuration.xml file of your installation you can find 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>

The configuration points to the locale configuration file such as the following one located in 02portal.war:/WEB-INF/conf/common/locales-config.xml:

<?xml version="1.0" encoding="UTF-8"?>
<locales-config>
  <locale-config>
    <locale>en(1)</locale>
    <output-en(2)coding>UTF-8</output-encoding>
    <input-enc(3)oding>UTF-8</input-encoding>
    <descripti(4)on>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>
    <description>Default configuration for the arabic locale</description>
    <orientati(5)on>rt</orientation>
  </locale-config>
</locales-config>
1

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

2

output-encoding Encoding It's highly recommended to always use UTF-8.

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 request setCharacterEncoding(..).

4

description Description for the language

5

description The default orientation of text and images is Left-To-Right. GateIn supports Right-To-Left orientation. Therefore you can define the orientation to use as explained in Section 5.2, “RTL (Right To Left) Framework”.

The resource bundle service is configured in: 02portal.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>
    <values-param>
      <name>cl(1)asspath.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>      
    <values-param>
      <name>in(2)it.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>      
    <values-param>
      <name>po(3)rtal.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 We will talk later about classpath.resources

2

init.resources TODO

3

portal.resource.names Defines all resources that belong to the Portal Resource Bundle. This means that these resources are merged to a single resource bundle which is accessible from anywhere in GateIn products. As mentioned, all these keys are located in the same bundle, which is separated from the navigation resource bundles.

classpath.resources

Portlets are independent application and they deliver their own resource files.

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

The inter application communication library can be found in 01eXoResources.war:/javascript/eXo/core/Topic.js

/**
 * publish is used to publish an event to the other subscribers to the given channels
 * @param {Object} senderId is a string that identify the sender
 * @param {String} topic is the topic that the message will be published
 * @param {Object} message is the message that's going to be delivered to the subscribers to the topic
 */
Topic.prototype.publish = function(/*Object*/ senderId, /*String*/ topicName, /*Object*/ message ) { ... }

/**
 * isSubscribed is used to check if a function receive the events from a topic
 * @param {String} topic The topic.
 * @param {Function} func is the name of the function of obj to call when a message is received on the topic
 */
Topic.prototype.isSubscribed = function(/*String*/ topic, /*Function*/ func) { ... }

/**
 * subscribe is used to subscribe a callback to a topic
 * @param {String} topic is the topic that will be listened
 * @param {Function} func is the name of the function of obj to call when a message is received on the topic
 * 
 * func is a function that take a Object in parameter. the event received have this format:
 * {senderId:senderId, message:message, topic: topic}
 *
 */
Topic.prototype.subscribe = function(/*String*/ topic, /*Function*/ func) { ... }

/**
 * unsubscribe is used to unsubscribe a callback to a topic
 * @param {String} topic is the topic
 * @param {Object} id is the id of the listener we want to unsubscribe
 */
Topic.prototype.unsubscribe = function(/*String*/ topic, /*Object*/ id) { ... }

Topic.prototype.initCometdBridge = function() { ... }

To use the component, you must create an object of type org.exoplatform.webui.form.UIFormUploadInput, using one of the two available constructors :

public UIFormUploadInput(String name, String bindingExpression)

or:

public UIFormUploadInput(String name, String bindingExpression, int limit)

Here is an example using the second form :

PortletRequestContext pcontext = (PortletRequestContext)WebuiRequestContext.getCurrentInstance();

PortletPreferences portletPref = pcontext.getRequest().getPreferences();
int limitMB = Integer.parseInt(portletPref.getValue("uploadFileSizeLimitMB", "").trim());
UIFormUploadInput uiInput = new UIFormUploadInput("upload", "upload", limitMB);

To get the limit from the xml configuration, you can add this piece of code in the files portlet.xml or portlet-preferences.xml :


<preference>
  <name>uploadFileSizeLimitMB</name>
  <value>30</value>
  <read-only>false</read-only>
</preference>

Again, a 0 value means unlimited upload size, and the value unit is set in MegaBytes.

To get the uploaded data use the getUploadDataAsStream() method:

UIFormUploadInput input = (UIFormUploadInput)uiForm.getUIInput("upload");

InputStream inputStream = input.getUploadDataAsStream();
...
jcrData.setValue(inputStream);

Clean the uploaded file

The upload service stores a temporary file on the filesystem during the process. When the upload is finished, you must clean the service in order to :

To do that, use theremoveUpload() method defined in the upload service, like this :

UploadService uploadService = uiForm.getApplicationComponent(UploadService.class) ;

UIFormUploadInput uiChild = uiForm.getChild(UIFormUploadInput.class) ;
uploadService.removeUpload(uiChild.getUploadId()) ;

Be sure to get and save the file before you clean the service

To retrieve the logged in user you can do as follows :

// Alternative context: WebuiRequestContext context = WebuiRequestContext.getCurrentInstance() ;

PortalRequestContext context = PortalRequestContext.getCurrentInstance() ;
// Get the id of the user logged
String userId = context.getRemoteUser();
// Request the information from OrganizationService:
OrganizationService orgService = getApplicationComponent(OrganizationService.class) ;
if (userId != null)
  {
  User user = orgService.getUserHandler().findUserByName(userId) ;
  if (user != null)
  {
    String firstName = user.getFirstName();
    String lastName = user.getLastName();
    String email = user.getEmail();
  }
}

Alternatives for retrieving the Organization Service