JBoss.orgCommunity Documentation

GateIn Documentation

GateIn

This is a very rough documentation issued from the merge, content still has to be validated, we still hope that it can help the beta testers. Thanks !


1. Introduction
1.1. Related Links
2. Configuration
2.1. PicketLink IDM integration
2.1.1. Configuration files
2.2. Default Portal Configuration
2.2.1. Overview
2.2.2. Configuration
2.3. Portal Navigation Configuration
2.3.1. Overview
2.3.2. Portal Navigation
2.3.3. Group Navigation
2.3.4. User Navigation
2.3.5. Tips
2.4. Predefined User Configuration
2.4.1. Overview
2.4.2. Plugin for adding users, groups and membership types
2.4.3. Membership types
2.4.4. Groups
2.4.5. Users
2.4.6. Plugin for monitoring user creation
2.5. Portal Default Permission Configuration
2.5.1. Overview
2.5.2. Overwrite Portal Default Permissions
2.6. Database Configuration
2.6.1. Overview
2.6.2. Configuring the database for JCR
2.6.3. Configuring the database for the default identity store
2.7. Data Injector Configuration
2.7.1. Data Injector
2.7.2. OrganizationInitializer
2.7.3. Group Parameters
2.7.4. User Parameters
2.7.5. Automatic Navigation Creation
2.8. Skin Configuration
2.8.1. Overview
2.8.2. Skin Switching
2.8.3. Types of skins
2.8.4. Skins in Page Markups
2.8.5. Set the default skin
2.8.6. How to create a new skin
2.8.7. How to create a new window style
2.8.8. How to create new Portlet skins
2.8.9. Tips and Tricks
2.9. Javascript Configuration
2.10. Dashboard configuration
2.11. Authentication Token Configuration
2.11.1. What is token service
2.11.2. Implement token service's API
2.11.3. Configure token services
3. Integration
4. SSO - Single Sign On
4.1. Overview
4.1.1. Prerequisite
4.2. CAS - Central Authentication Service
4.2.1. CAS server
4.2.2. Setup the CAS client
4.2.3. Setup the portal to redirect to CAS
4.3. JOSSO
4.3.1. JOSSO server
4.3.2. Setup the JOSSO client
4.3.3. Setup the portal to redirect to JOSSO
4.4. OpenSSO - The Open Web SSO project
4.4.1. OpenSSO server
4.4.2. Setup the OpenSSO client
4.4.3. Setup the portal to redirect to OpenSSO
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. Groovy templates
5.2.2. Stylesheet
5.2.3. Images
5.2.4. 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. XML format
5.4.3. Portal support
5.5. Dynamic Layouts
5.5.1. Overview
5.5.2. Advanced Drag and Drop mechanism
5.6. JavaScript Inter Application Communication
5.6.1. Overview
5.6.2. Library
5.6.3. Syntax
5.6.4. Example [of what?]
5.7. Upload Component
5.7.1. Upload Service
5.8. Deactivation of the Ajax Loading Mask Layer
5.8.1. Purpose
5.8.2. Synchronous issue
5.9. Accessing User Profile
6. Portlet development
6.1. Web User Interface - WebUI
6.1.1. Relevant Sections
6.2. AJAX Framework
6.2.1. Portlet Preparation
6.2.2. AJAX in Groovy
6.2.3. How JavaScript works
6.2.4. PortletResponse
6.2.5. PortalResponse
6.2.6. AjaxRequest
6.2.7. HttpResponseHandler
6.2.8. Manage Several Popups
6.3. Groovy Templates
6.3.1. Basic structure
6.3.2. Groovy language
6.3.3. Linking a portlet with a template
6.4. Portlet Lifecycle
6.4.1. Portlet init
6.4.2. Portlet request handler
6.4.3. ProcessAction phase
6.4.4. Render phase
6.5. Portlet Primer
6.5.1. JSR-168 and JSR-286 overview
6.5.2. Tutorials
6.6. Create a WebUI Portlet
6.6.1. Overview
6.6.2. Configure the portlet
6.6.3. Use the Portlet
6.6.4. Add a "HelloWorld" popup
7. Gadget development
7.1. Gadgets
7.1.1. Existing Gadgets
7.1.2. Create a new Gadget
7.1.3. Remote Gadget
7.1.4. Gadget Importing
7.1.5. Gadget Web Editing
7.1.6. Gadget IDE Editing
7.1.7. Dashboard Viewing
7.2. Setup a Gadget Server
7.2.1. Virtual servers for gadget rendering
7.2.2. Configuration

is a merge of two mature projects; JBoss Portal and eXo Portal. It takes the best of both offerings and incorporates them into a single new project. The aim is to provide an intuitive portal for as-is use and a framework to build upon depending on your needs.

This book explains how to configure various aspects of , including navigation, skins and database variables.

Refer to the Installation Guide for information on downloading and installing the product or the User Guide for information on basic usage.

GateIn 3.0 uses the PicketLink IDM component to retain necessary identity information (user, groups, memberships, etc.). While legacy interfaces are still used (org.exoplatform.services.organization) for identity management, the wrapper implementation delegates to the PicketLink IDM framework.

This section doesn't provide information about PicketLink IDM and its configuration. Please refer to the appropriate project documentation (http://jboss.org/picketlink/IDM.html) for further information.

Note

It is important to fully understand the concepts behind this framework design before changing the default configuration.

The identity model represented in 'org.exoplatform.services.organization' interfaces and the one used in PicketLink IDM have some major differences.

For example: the PicketLink IDM provides greater abstraction. It is possible for groups in the IDM framework to form memberships with many parents (which requires recursive ID translation) while the GateIn model allows only pure tree like membership structures.

Additionally the GateIn membership concept needs to be translated into the IDM Role concept. Therefore PicketLink IDM model is used in a limited way. All these translations are applied by the integration layer.

The main configuration file is idm-configuration:


<configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://www.exoplaform.org/xml/ns/kernel_1_0.xsd http://www.exoplaform.org/xml/ns/kernel_1_0.xsd"
               xmlns="http://www.exoplaform.org/xml/ns/kernel_1_0.xsd">
(1)ml_plain">
   <component>
        <key>org.exoplatform.services.organization.idm.PicketLinkIDMService</key>
      <type>org.exoplatform.services.organization.idm.PicketLinkIDMServiceImpl</type>
      <init-params>
         <value-param>
            <name>config</name>
            <value>war:/conf/organization/idm-config.xml</value>
         </value-param>
         <value-param>
            <name>portalRealm</name>
            <value>realm${container.name.suffix}</value>
         </value-param>
       </init-params>
   </component>


(2)ml_plain">   <component>
      <key>org.exoplatform.services.organization.OrganizationService</key>
      <type>org.exoplatform.services.organization.idm.PicketLinkIDMOrganizationServiceImpl</type>
      <init-params>
      <object-param>
        <name>configuration</name>
        <object type="org.exoplatform.services.organization.idm.Config">
          <field name="useParentIdAsGroupType">
            <boolean>true</boolean>
          </field>

          <field name="forceMembershipOfMappedTypes">
            <boolean>true</boolean>
          </field>

          <field name="pathSeparator">
            <string>.</string>
          </field>

          <field name="rootGroupName">
            <string>GTN_ROOT_GROUP</string>
          </field>

          <field name="groupTypeMappings">
            <map type="java.util.HashMap">
              <entry>
                <key><string>/</string></key>
                <value><string>root_type</string></value>
              </entry>

              <!-- Sample mapping -->
              <!--
              <entry>
                <key><string>/platform/*</string></key>
                <value><string>platform_type</string></value>
              </entry>
              <entry>
                <key><string>/organization/*</string></key>
                <value><string>organization_type</string></value>
              </entry>
              -->

            </map>
          </field>

          <field name="associationMembershipType">
            <string>member</string>
          </field>

          <field name="ignoreMappedMembershipType">
            <boolean>false</boolean>
          </field>
        </object>
      </object-param>
    </init-params>


   </component>

</configuration>
1

The org.exoplatform.services.organization.idm.PicketLinkIDMServiceImpl service has following options:

  • config - (value-param) - PicketLink IDM configuration file

  • jndiName - (value-param) - in case 'config' parameter is not provided this will be used to perform JNDI lookup for IdentitySessionFactory

  • portalRealm - (value-param) - name of a realm that should be used to obtain proper IdentitySession - default is 'PortalRealm'.

2

The org.exoplatform.services.organization.idm.PicketLinkIDMOrganizationServiceImpl key is a main entrypoint implementing org.exoplatform.services.organization.OrganizationService and is dependant on org.exoplatform.services.organization.idm.PicketLinkIDMService

org.exoplatform.services.organization.idm.PicketLinkIDMOrganizationServiceImpl service has following options defined as fields of object-param type org.exoplatform.services.organization.idm.Config:

  • defaultGroupType - Name of PicketLink IDM GroupType that will be used to store groups. Default is 'GTN_GROUP_TYPE'

  • rootGroupName - Name of PicketLink IDM Group that will be used as a root parent. Default is 'GTN_ROOT_GROUP'

  • passwordAsAttribute - (default false) - Specifies if password should be stored using PicketLink IDM Credential object or as a plain attribute

  • useParentIdAsGroupType - For all ids not mapped with type in 'groupTypeMappings' option use parent id path as a group type to store group in PicketLink IDM. The effect of setting this option to false and not providing any mappings under 'groupTypeMappings' option is that there can be only one group with a given name in whole GateIn group tree

  • pathSeparator - When 'userParentIdAsGroupType is set to true this value will be used to replace all "/" chars in id. This is because "/" is not allowed to be used in group type name in PicketLink IDM

  • associationMembershipType - If this option is used then each Membership created with MembrshipType that is equal to value specified here will be stored in PicketLink IDM as simple Group-User association

  • groupTypeMappings - Map groups added with GateIn API as a childs of a given group ID to be stored with a given group type name in PicketLink IDM. If parent ID ends with "/*" then all child groups will have the mapped group type. Otherwise only direct (first level) children will use this type. This can be leveraged by LDAP setup. Given LDAP DN configured in PicketLink IDM to store specific group type will then store one given branch in GateIn group tree while all other groups will remain in DB.

  • forceMembershipOfMappedTypes - Group stored in PicketLink IDM with a type mapped in 'groupTypeMappings' will automatically be member under mapped parent. Normally groups are linked by PicketLink IDM group association - such relationship won't be needed then. It can be set to false if all groups are added via GateIn APIs This option may be useful with LDAP config as it will make (if set to true) every entry added to LDAP (not via GateIn management UI) appear in GateIn

  • ignoreMappedMembershipType - if "associationMembershipType" option is used and this option is set to true then Membership with MembershipType configured to be stored as PicketLink IDM association will not be stored as PicketLink IDM Role

Additionally JBossIDMOrganizationServiceImpl uses those defaults to perform identity management operations

  • GateIn User interface properties fields are persisted in JBoss Identity IDM using those attributes names: firstName, lastName, email, createdDate, lastLoginTime, organizationId, password (if password is configured to be stored as attribute)

  • GateIn Group interface properties fields are persisted in JBoss Identity IDM using those attributes names: label, description

  • GateIn MembershipType interface properties fields are persisted in JBoss Identity IDM using those RoleType properties: description, owner, create_date, modified_date

A sample PicketLink IDM configuration file is shown below. To understand all the options present in it please refer to the PicketLink IDM Reference Guide

<jboss-identity xmlns="urn:jboss:identity:idm:config:v1_0_beta"
                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                xsi:schemaLocation="urn:jboss:identity:idm:config:v1_0_alpha identity-config.xsd">
    <realms>
        <realm>
            <id>PortalRealm</id>
            <repository-id-ref>PortalRepository</repository-id-ref>
            <identity-type-mappings>
                <user-mapping>USER</user-mapping>
            </identity-type-mappings>
        </realm>
    </realms>
    <repositories>
        <repository>
            <id>PortalRepository</id>
            <class>org.jboss.identity.idm.impl.repository.WrapperIdentityStoreRepository</class>
            <external-config/>
            <default-identity-store-id>HibernateStore</default-identity-store-id>
            <default-attribute-store-id>HibernateStore</default-attribute-store-id>
        </repository>
    </repositories>
    <stores>
        <attribute-stores/>
        <identity-stores>
            <identity-store>
                <id>HibernateStore</id>
                <class>org.jboss.identity.idm.impl.store.hibernate.HibernateIdentityStoreImpl</class>
                <external-config/>
                <supported-relationship-types>
                    <relationship-type>JBOSS_IDENTITY_MEMBERSHIP</relationship-type>
                    <relationship-type>JBOSS_IDENTITY_ROLE</relationship-type>
                </supported-relationship-types>
                <supported-identity-object-types>
                    <identity-object-type>
                        <name>USER</name>
                        <relationships/>
                        <credentials>
                            <credential-type>PASSWORD</credential-type>
                        </credentials>
                        <attributes/>
                        <options/>
                    </identity-object-type>
                </supported-identity-object-types>
                <options>
                    <option>
                        <name>hibernateSessionFactoryRegistryName</name>
                        <value>hibernateSessionFactory</value>
                    </option>
                    <option>
                        <name>allowNotDefinedIdentityObjectTypes</name>
                        <value>true</value>
                    </option>
                    <option>
                        <name>populateRelationshipTypes</name>
                        <value>true</value>
                    </option>
                    <option>
                        <name>populateIdentityObjectTypes</name>
                        <value>true</value>
                    </option>
                    <option>
                        <name>allowNotDefinedAttributes</name>
                        <value>true</value>
                    </option>
                    <option>
                        <name>isRealmAware</name>
                        <value>true</value>
                    </option>
                </options>
            </identity-store>
        </identity-stores>
    </stores>
</jboss-identity>

Three types of navigation are available to portal users:

These navigations are configured with standard XML syntax in the file; "02portal.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> 
       <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>
               <value><string>webos</string></value>
             </collection>
           </field>
           <field  name="ownerType"><string>portal</string></field>
           <field  name="templateLocation"><string>war:/conf/portal</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> 
         </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>
             </collection>
           </field>
           <field  name="ownerType"><string>user</string></field>
           <field  name="templateLocation"><string>war:/conf/portal</string></field> 
         </object>
       </object-param>
     </init-params>
   </component-plugin>
</component-plugins>

This XML file defines, for the three navigations, which sets of portals, groups or users will have XML files inside the apprpriate war. Those files will be used to create an initial navigation the first time the portal is launched. That information will then be stored in the JCR and is then modifiable from the portal UI.

The portal navigation incorporates the pages that can be accessed when the user is not logged in (if the applicable permissions allow public access). For example; several portal navigations are used when a company has multiple trademarks and each trade has its own website.

The classic portal is configured by four XML files in the portal/WEBINF/conf/portal/portal/classic directory:

Portal.xml

This file describes the layout and portlets that will be shown on all pages. Usually the layout contains the banner, footer, menu and breadcrumbs portlets. is extremely configurable as every area (even the banner and footer) is a portlet.


<?xml version="1.0" encoding="ISO-8859-1"?>
<portal-config>
  <portal-name>classic</portal-name>
  <locale>en</locale>
  <factory-id>office</factory-id>
  <access-permissions>Everyone</access-permissions>
  <edit-permission>*:/platform/administrators</edit-permission>
  <creator>root</creator>    
    
  <portal-layout>   
  <application>
     <instance-id>portal#classic:/web/BannerPortlet/banner</instance-id>
     <show-info-bar>false</show-info-bar>
   </application>
   <application>
    <instance-id>portal#classic:/web/NavigationPortlet/toolbar</instance-id>
     <show-info-bar>false</show-info-bar>
   </application>
  
   <application>
     <instance-id>portal#classic:/web/BreadcumbsPortlet/breadcumbs</instance-id>
     <show-info-bar>false</show-info-bar>
   </application>
   
 
   <page-body> </page-body>
   
   <application>
     <instance-id>portal#classic:/web/FooterPortlet/footer</instance-id>
     <show-info-bar>false</show-info-bar>
   </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 of the layout of their child portlets.

Each application references a portlet using the id portal#{portalName}:/{portletWarName}/{portletName}/{uniqueId}

Use the page-body tag to define where 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 the portal will have. The syntax is simple, using nested node tags. Each node references a page that is defined in the next XML file.

If the label #{} node label is used, the internationalization mechanism is activated and the actual label to render is taken from an associated properties file for the current locale.


<?xml version="1.0" encoding="UTF-8"?>
<node-navigation>
  <owner-type>portal</owner-type>
  <owner-id>classic</owner-id>
  <priority>1</priority>
  <page-nodes>
   <node>
     <uri>home</uri>
     <name>home</name>
     <label>#{portal.classic.home}</label>
     <page-reference>portal::classic::homepage</page-reference>     
   </node>    
   <node>
     <uri>webexplorer</uri>
     <name>webexplorer</name>
     <label>#{portal.classic.webexplorer}</label>
     <page-reference>portal::classic::webexplorer</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 XML 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 icons or the mode.


<?xml version="1.0" encoding="ISO-8859-1"?>
<page-set>  
  <page>
    <page-id>portal::classic::homepage</page-id>
    <owner-type>portal</owner-type>
    <owner-id>classic</owner-id>
    <name>homepage</name>
    <title>Home Page</title>
    <access-permissions>Everyone</access-permissions>
    <edit-permission>*:/platform/administrators</edit-permission>
    <application>
      <instance-id>portal#classic:/web/HomePagePortlet/homepageportlet</instance-id>
      <title>Home Page portlet</title>
      <show-info-bar>false</show-info-bar>
      <show-application-state>false</show-application-state>
      <show-application-mode>false</show-application-mode>
    </application>
  </page>    
    
  <page>
    <page-id>portal::classic::webexplorer</page-id>
    <owner-type>portal</owner-type>
    <owner-id>classic</owner-id>
    <name>webexplorer</name>
    <title>Web Explorer</title>
    <access-permissions>*:/platform/users</access-permissions>
    <edit-permission>*:/platform/administrators</edit-permission>    
    <application>
      <instance-id>group#platform/users:/web/BrowserPortlet/WebExplorer</instance-id>
      <title>Web Explorer</title>
      <show-info-bar>false</show-info-bar>
    </application>  
  </page>  
</page-set>
Portlet-preferences.xml

Porlet instances can be associated with portlet-preferences that override the one defined in portlet.xml file of the portlet application war .


<?xml version="1.0" encoding="ISO-8859-1"?>
<portlet-preferences-set>
  <portlet-preferences>
    <owner-type>portal</owner-type>
    <owner-id>classic</owner-id>
    <window-id>portal#classic:/web/BannerPortlet/banner</window-id>
    <preference>
      <name>template</name>
      <value>par:/groovy/groovy/webui/component/UIBannerPortlet.gtmpl</value>
      <read-only>false</read-only>
    </preference>
  </portlet-preferences>
  <portlet-preferences>
    <owner-type>portal</owner-type>
    <owner-id>classic</owner-id>
    <window-id>portal#classic:/web/NavigationPortlet/toolbar</window-id>
    <preference>
      <name>useAJAX</name>
      <value>true</value>
      <read-only>false</read-only>
    </preference>
  </portlet-preferences>
  <portlet-preferences>
    <owner-type>portal</owner-type>
    <owner-id>classic</owner-id>
    <window-id>portal#classic:/web/FooterPortlet/footer</window-id>
    <preference>
      <name>template</name>
      <value>par:/groovy/groovy/webui/component/UIFooterPortlet.gtmpl</value>
      <read-only>false</read-only>
    </preference>
  </portlet-preferences>
  
  
  <portlet-preferences>
    <owner-type>portal</owner-type>
    <owner-id>classic</owner-id>
    <window-id>portal#classic:/web/GroovyPortlet/groovyportlet</window-id>
    <preference>
      <name>template</name>
      <value>par:/groovy/groovy/webui/component/UIGroovyPortlet.gtmpl</value>
      <read-only>false</read-only>
    </preference>
  </portlet-preferences>
</portlet-preferences-set>

The user navigation is the set of nodes and pages that are owned by a user. They are part of the user dashboard.

Three files configure the user navigation (navigation.xml, pages.xml and portlet-preferences.xml). They are located in the directory "portal/WEB-INF/conf/portal/users/{userName}".

This directory also contains a gadgets.xml file (which was formerly called widgets.xml). This file defines the gadgets located in the user workspace.

The user workspace is located at the left hand side of the page and access is restricted to some privileged users, see Section 2.4, “Predefined User Configuration”


<?xml version="1.0" encoding="ISO-8859-1"?>
<widgets>
  <owner-type>user</owner-type>
  <owner-id>root</owner-id>
 
  <container id="Information">
    <name>Information</name>
    <description>Information's Description</description>
    <application>
      <instance-id>user#root:/GateInWidgetWeb/WelcomeWidget/WelcomeWidget1</instance-id>
      <application-type>GateInWidget</application-type>
    </application>
      
    <application>
      <instance-id>user#root:/GateInWidgetWeb/StickerWidget/StickerWidget</instance-id>
      <application-type>GateInWidget</application-type> 
    </application>
    
    <application>
      <instance-id>user#root:/GateInWidgetWeb/InfoWidget/InfoWidget1</instance-id>
      <application-type>GateInWidget</application-type>
    </application>
  </container>
  
  <container id="Calendar">
    <name>Calendar</name>
    <description>Calendar's Description</description>
    <application>
      <instance-id>user#root:/GateInWidgetWeb/CalendarWidget/CalendarWidget</instance-id>
      <application-type>GateInWidget</application-type> 
    </application>
  </container> 
 
</widgets>

The plugin of type org.exoplatform.services.organization.impl.NewUserEventListener specifies which groups should join all newly created users. It notably specifies the groups and memberships to be used. It also specifies a list of users that should be excepted.


<component-plugin>
  <name>new.user.event.listener</name>
  <set-method>addListenerPlugin</set-method>
  <type>org.exoplatform.services.organization.impl.NewUserEventListener</type>
  <description>this listener assign group and membership to a new created user</description>
  <init-params>
    <object-param>
      <name>configuration</name>
      <description>description</description>
      <object type="org.exoplatform.services.organization.impl.NewUserConfig">
        <field  name="group">
          <collection type="java.util.ArrayList">
            <value>
              <object type="org.exoplatform.services.organization.impl.NewUserConfig$JoinGroup">
                <field name="groupId"><string>/user</string></field>
                <field name="membership"><string>member</string></field>
              </object>
            </value>               
          </collection>
        </field>
        <field  name="ignoredUser">
          <collection type="java.util.HashSet">
            <value><string>exo</string></value>
            <value><string>root</string></value>
            <value><string>company</string></value>
            <value><string>community</string></value>
          </collection>
        </field>
      </object>
    </object-param>
  </init-params>
</component-plugin>

The permission configuration for the portal is defined in the file 02portal.war:/WEB-INF/conf/portal/portal-configuration.xml . The component UserACL is described there along with other portal component configurations.

It defines 5 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>

To configure the databaseused by JCR you will need to edit the file:

gatein.ear/02portal.war/WEB-INF/conf/jcr/jcr-configuration.xml

And edit the values of driverClassName, url, username and password with the values for your JDBC connection (Please refer to your database JDBC driver documentation).


<properties-param>
  <name>ref-addresses</name>
  <description>ref-addresses</description>
  <property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
  <property name="url" value="jdbc:hsqldb:file:${gatein.db.data.dir}/data/jdbcjcr${container.name.suffix}"/>
  property name="username" value="sa"/>
  <property name="password" value=""/>
</properties-param>

In that case, the name of the database is "jdbcjcr${container.name.suffix}", ${container.name.suffix} should be part of the database name, as it is dynamically replaced by the name of the portal extension (for instance gatein-sample-portal.ear defines "sample-portal" as container name and the default portal defines "portal" as container name).

In the case of HSQL the databases are created automatically, for any other database you will need to create a database named jdbcjcr_portal (and "jdbcjcr_sample-portal" if you kept gatein-sample-portal.ear in $JBOSS_HOME/server/default/deploy. Note that some database wont accept '-' in a database name and you will have to delete $JBOSS_HOME/server/default/deploy/gatein-sample-portal.ear)

Make sure the user has rights to create tables on jdbcjcr_portal and to update them as during the first startup they will be automatically created.

Also add the JDBC driver into the classpath, for instance in $JBOSS_HOME/server/default/lib (or $TOMCAT_HOME/lib if you are running on Tomcat)

MySQL example:

Let's configure our JCR to store data in MySQL, let's pretend we have a user named "gateinuser" with a password "gateinpassword". We would create a database "mygateindb_portal" (Remember that _portal is required) and assign him the rights to create tables.

Then we need to add the MySQL JDBC connector in the classpath and finally edit gatein.ear/02portal.war/WEB-INF/conf/jcr/jcr-configuration with:

<properties-param>
  <name>ref-addresses</name>
  <description>ref-addresses</description>
  <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
  <property name="url" value="jdbc:mysql://localhost:3306/mygateindb${container.name.suffix}"/>
  <property name="username" value="gateinuser"/>
  <property name="password" value="gateinpassword"/>
</properties-param>

OrganizationInitializer is the service that allows creating a large organization with many groups and users. It also creates portal navigation and page(s) for each group and each user.

Service configuration file

<!-- XML : generated by JHighlight v1.0 (http://jhighlight.dev.java.net) -->
<span class="xml_tag_symbols">&lt;</span><span class="xml_tag_name">configuration</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain"></span><br />
<span class="xml_plain">&nbsp;&nbsp;</span><span class="xml_tag_symbols">&lt;</span><span class="xml_tag_name">component</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain"></span><br />
<span class="xml_plain">&nbsp;&nbsp;</span><span class="xml_tag_symbols">&lt;</span><span class="xml_tag_name">key</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain">org.exoplatform.portal.initializer.organization.OrganizationInitializer</span><span class="xml_tag_symbols">&lt;/</span><span class="xml_tag_name">key</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain"></span><br />
<span class="xml_plain">&nbsp;&nbsp;</span><span class="xml_tag_symbols">&lt;</span><span class="xml_tag_name">type</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain">org.exoplatform.portal.initializer.organization.OrganizationInitializer</span><span class="xml_tag_symbols">&lt;/</span><span class="xml_tag_name">type</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain"></span><br />
<span class="xml_plain">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="xml_tag_symbols">&lt;</span><span class="xml_tag_name">init-params</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain"></span><br />
<span class="xml_plain">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="xml_tag_symbols">&lt;</span><span class="xml_tag_name">value-param</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain"></span><br />
<span class="xml_plain">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="xml_tag_symbols">&lt;</span><span class="xml_tag_name">name</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain">auto.create.group.page.navigation</span><span class="xml_tag_symbols">&lt;/</span><span class="xml_tag_name">name</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain"></span><br />
<span class="xml_plain">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="xml_tag_symbols">&lt;</span><span class="xml_tag_name">description</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain">true&nbsp;or&nbsp;false</span><span class="xml_tag_symbols">&lt;/</span><span class="xml_tag_name">description</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain"></span><br />
<span class="xml_plain">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="xml_tag_symbols">&lt;</span><span class="xml_tag_name">value</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain">true</span><span class="xml_tag_symbols">&lt;/</span><span class="xml_tag_name">value</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain"></span><br />
<span class="xml_plain">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="xml_tag_symbols">&lt;/</span><span class="xml_tag_name">value-param</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain"></span><br />
<span class="xml_plain">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><br />
<span class="xml_plain">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="xml_tag_symbols">&lt;</span><span class="xml_tag_name">value-param</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain"></span><br />
<span class="xml_plain">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="xml_tag_symbols">&lt;</span><span class="xml_tag_name">name</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain">auto.create.user.page.navigation</span><span class="xml_tag_symbols">&lt;/</span><span class="xml_tag_name">name</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain"></span><br />
<span class="xml_plain">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="xml_tag_symbols">&lt;</span><span class="xml_tag_name">description</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain">number&nbsp;of&nbsp;pages&nbsp;per&nbsp;user</span><span class="xml_tag_symbols">&lt;/</span><span class="xml_tag_name">description</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain"></span><br />
<span class="xml_plain">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="xml_tag_symbols">&lt;</span><span class="xml_tag_name">value</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain">10</span><span class="xml_tag_symbols">&lt;/</span><span class="xml_tag_name">value</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain"></span><br />
<span class="xml_plain">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="xml_tag_symbols">&lt;/</span><span class="xml_tag_name">value-param</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain"></span><br />
<span class="xml_plain">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><br />
<span class="xml_plain">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="xml_tag_symbols">&lt;</span><span class="xml_tag_name">object-param</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain"></span><br />
<span class="xml_plain">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="xml_tag_symbols">&lt;</span><span class="xml_tag_name">name</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain">organization</span><span class="xml_tag_symbols">&lt;/</span><span class="xml_tag_name">name</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain"></span><br />
<span class="xml_plain">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="xml_tag_symbols">&lt;</span><span class="xml_tag_name">description</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain">description</span><span class="xml_tag_symbols">&lt;/</span><span class="xml_tag_name">description</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain"></span><br />
<span class="xml_plain">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="xml_tag_symbols">&lt;</span><span class="xml_tag_name">object</span><span class="xml_plain">&nbsp;</span><span class="xml_attribute_name">type</span><span class="xml_tag_symbols">=</span><span class="xml_attribute_value">&quot;org.exoplatform.portal.initializer.organization.OrganizationConfig&quot;</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain"></span><br />
<span class="xml_plain">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="xml_tag_symbols">&lt;</span><span class="xml_tag_name">field</span><span class="xml_plain">&nbsp;</span><span class="xml_attribute_name">name</span><span class="xml_tag_symbols">=</span><span class="xml_attribute_value">&quot;groups&quot;</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain"></span><br />
<span class="xml_plain">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="xml_tag_symbols">&lt;</span><span class="xml_tag_name">collection</span><span class="xml_plain">&nbsp;</span><span class="xml_attribute_name">type</span><span class="xml_tag_symbols">=</span><span class="xml_attribute_value">&quot;java.util.ArrayList&quot;</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain"></span><br />
<span class="xml_plain">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="xml_tag_symbols">&lt;</span><span class="xml_tag_name">value</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain"></span><br />
<span class="xml_plain">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="xml_tag_symbols">&lt;</span><span class="xml_tag_name">object</span><span class="xml_plain">&nbsp;</span><span class="xml_attribute_name">type</span><span class="xml_tag_symbols">=</span><span class="xml_attribute_value">&quot;org.exoplatform.portal.initializer.organization.OrganizationConfig$GroupsConfig&quot;</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain"></span><br />
<span class="xml_plain">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="xml_tag_symbols">&lt;</span><span class="xml_tag_name">field</span><span class="xml_plain">&nbsp;</span><span class="xml_attribute_name">name</span><span class="xml_tag_symbols">=</span><span class="xml_attribute_value">&quot;group&quot;</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain"></span><br />
<span class="xml_plain">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="xml_tag_symbols">&lt;</span><span class="xml_tag_name">object</span><span class="xml_plain">&nbsp;</span><span class="xml_attribute_name">type</span><span class="xml_tag_symbols">=</span><span class="xml_attribute_value">&quot;org.exoplatform.services.organization.OrganizationConfig$Group&quot;</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain"></span><br />
<span class="xml_plain">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="xml_tag_symbols">&lt;</span><span class="xml_tag_name">field</span><span class="xml_plain">&nbsp;</span><span class="xml_attribute_name">name</span><span class="xml_tag_symbols">=</span><span class="xml_attribute_value">&quot;name&quot;</span><span class="xml_tag_symbols">&gt;&lt;</span><span class="xml_tag_name">string</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain">province</span><span class="xml_tag_symbols">&lt;/</span><span class="xml_tag_name">string</span><span class="xml_tag_symbols">&gt;&lt;/</span><span class="xml_tag_name">field</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain"></span><br />
<span class="xml_plain">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="xml_tag_symbols">&lt;</span><span class="xml_tag_name">field</span><span class="xml_plain">&nbsp;</span><span class="xml_attribute_name">name</span><span class="xml_tag_symbols">=</span><span class="xml_attribute_value">&quot;parentId&quot;</span><span class="xml_tag_symbols">&gt;&lt;</span><span class="xml_tag_name">string</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain">/africa/tanzania</span><span class="xml_tag_symbols">&lt;/</span><span class="xml_tag_name">string</span><span class="xml_tag_symbols">&gt;&lt;/</span><span class="xml_tag_name">field</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain"></span><br />
<span class="xml_plain">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="xml_tag_symbols">&lt;</span><span class="xml_tag_name">field</span><span class="xml_plain">&nbsp;</span><span class="xml_attribute_name">name</span><span class="xml_tag_symbols">=</span><span class="xml_attribute_value">&quot;description&quot;</span><span class="xml_tag_symbols">&gt;&lt;</span><span class="xml_tag_name">string</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain">Tanzania's&nbsp;province</span><span class="xml_tag_symbols">&lt;/</span><span class="xml_tag_name">string</span><span class="xml_tag_symbols">&gt;&lt;/</span><span class="xml_tag_name">field</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain"></span><br />
<span class="xml_plain">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="xml_tag_symbols">&lt;</span><span class="xml_tag_name">field</span><span class="xml_plain">&nbsp;</span><span class="xml_attribute_name">name</span><span class="xml_tag_symbols">=</span><span class="xml_attribute_value">&quot;label&quot;</span><span class="xml_tag_symbols">&gt;&lt;</span><span class="xml_tag_name">string</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain">Province</span><span class="xml_tag_symbols">&lt;/</span><span class="xml_tag_name">string</span><span class="xml_tag_symbols">&gt;&lt;/</span><span class="xml_tag_name">field</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain"></span><br />
<span class="xml_plain">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="xml_tag_symbols">&lt;/</span><span class="xml_tag_name">object</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><br />
<span class="xml_plain">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="xml_tag_symbols">&lt;/</span><span class="xml_tag_name">field</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain">&nbsp;</span><br />
<span class="xml_plain">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="xml_tag_symbols">&lt;</span><span class="xml_tag_name">field</span><span class="xml_plain">&nbsp;</span><span class="xml_attribute_name">name</span><span class="xml_tag_symbols">=</span><span class="xml_attribute_value">&quot;from&quot;</span><span class="xml_tag_symbols">&gt;&lt;</span><span class="xml_tag_name">string</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain">1</span><span class="xml_tag_symbols">&lt;/</span><span class="xml_tag_name">string</span><span class="xml_tag_symbols">&gt;&lt;/</span><span class="xml_tag_name">field</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain"></span><br />
<span class="xml_plain">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="xml_tag_symbols">&lt;</span><span class="xml_tag_name">field</span><span class="xml_plain">&nbsp;</span><span class="xml_attribute_name">name</span><span class="xml_tag_symbols">=</span><span class="xml_attribute_value">&quot;to&quot;</span><span class="xml_tag_symbols">&gt;&lt;</span><span class="xml_tag_name">string</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain">10</span><span class="xml_tag_symbols">&lt;/</span><span class="xml_tag_name">string</span><span class="xml_tag_symbols">&gt;&lt;/</span><span class="xml_tag_name">field</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain"></span><br />
<span class="xml_plain">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="xml_tag_symbols">&lt;/</span><span class="xml_tag_name">object</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain"></span><br />
<span class="xml_plain">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="xml_tag_symbols">&lt;/</span><span class="xml_tag_name">value</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain"></span><br />
<span class="xml_plain">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="xml_tag_symbols">&lt;/</span><span class="xml_tag_name">collection</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain"></span><br />
<span class="xml_plain">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="xml_tag_symbols">&lt;/</span><span class="xml_tag_name">field</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain"></span><br />
<span class="xml_plain">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="xml_tag_symbols">&lt;</span><span class="xml_tag_name">field</span><span class="xml_plain">&nbsp;</span><span class="xml_attribute_name">name</span><span class="xml_tag_symbols">=</span><span class="xml_attribute_value">&quot;users&quot;</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain"></span><br />
<span class="xml_plain">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="xml_tag_symbols">&lt;</span><span class="xml_tag_name">collection</span><span class="xml_plain">&nbsp;</span><span class="xml_attribute_name">type</span><span class="xml_tag_symbols">=</span><span class="xml_attribute_value">&quot;java.util.ArrayList&quot;</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain">&nbsp;</span><br />
<span class="xml_plain">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="xml_tag_symbols">&lt;</span><span class="xml_tag_name">value</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain"></span><br />
<span class="xml_plain">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="xml_tag_symbols">&lt;</span><span class="xml_tag_name">object</span><span class="xml_plain">&nbsp;</span><span class="xml_attribute_name">type</span><span class="xml_tag_symbols">=</span><span class="xml_attribute_value">&quot;org.exoplatform.portal.initializer.organization.OrganizationConfig$UsersConfig&quot;</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain"></span><br />
<span class="xml_plain">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="xml_tag_symbols">&lt;</span><span class="xml_tag_name">field</span><span class="xml_plain">&nbsp;</span><span class="xml_attribute_name">name</span><span class="xml_tag_symbols">=</span><span class="xml_attribute_value">&quot;user&quot;</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain"></span><br />
<span class="xml_plain">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="xml_tag_symbols">&lt;</span><span class="xml_tag_name">object</span><span class="xml_plain">&nbsp;</span><span class="xml_attribute_name">type</span><span class="xml_tag_symbols">=</span><span class="xml_attribute_value">&quot;org.exoplatform.services.organization.OrganizationConfig$User&quot;</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain"></span><br />
<span class="xml_plain">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="xml_tag_symbols">&lt;</span><span class="xml_tag_name">field</span><span class="xml_plain">&nbsp;</span><span class="xml_attribute_name">name</span><span class="xml_tag_symbols">=</span><span class="xml_attribute_value">&quot;userName&quot;</span><span class="xml_tag_symbols">&gt;&lt;</span><span class="xml_tag_name">string</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain">user</span><span class="xml_tag_symbols">&lt;/</span><span class="xml_tag_name">string</span><span class="xml_tag_symbols">&gt;&lt;/</span><span class="xml_tag_name">field</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain"></span><br />
<span class="xml_plain">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="xml_tag_symbols">&lt;</span><span class="xml_tag_name">field</span><span class="xml_plain">&nbsp;</span><span class="xml_attribute_name">name</span><span class="xml_tag_symbols">=</span><span class="xml_attribute_value">&quot;password&quot;</span><span class="xml_tag_symbols">&gt;&lt;</span><span class="xml_tag_name">string</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain">GateInPlatform</span><span class="xml_tag_symbols">&lt;/</span><span class="xml_tag_name">string</span><span class="xml_tag_symbols">&gt;&lt;/</span><span class="xml_tag_name">field</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain"></span><br />
<span class="xml_plain">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="xml_tag_symbols">&lt;</span><span class="xml_tag_name">field</span><span class="xml_plain">&nbsp;</span><span class="xml_attribute_name">name</span><span class="xml_tag_symbols">=</span><span class="xml_attribute_value">&quot;firstName&quot;</span><span class="xml_tag_symbols">&gt;&lt;</span><span class="xml_tag_name">string</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain">First-Name</span><span class="xml_tag_symbols">&lt;/</span><span class="xml_tag_name">string</span><span class="xml_tag_symbols">&gt;&lt;/</span><span class="xml_tag_name">field</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain"></span><br />
<span class="xml_plain">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="xml_tag_symbols">&lt;</span><span class="xml_tag_name">field</span><span class="xml_plain">&nbsp;</span><span class="xml_attribute_name">name</span><span class="xml_tag_symbols">=</span><span class="xml_attribute_value">&quot;lastName&quot;</span><span class="xml_tag_symbols">&gt;&lt;</span><span class="xml_tag_name">string</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain">Last-Name</span><span class="xml_tag_symbols">&lt;/</span><span class="xml_tag_name">string</span><span class="xml_tag_symbols">&gt;&lt;/</span><span class="xml_tag_name">field</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain"></span><br />
<span class="xml_plain">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="xml_tag_symbols">&lt;</span><span class="xml_tag_name">field</span><span class="xml_plain">&nbsp;</span><span class="xml_attribute_name">name</span><span class="xml_tag_symbols">=</span><span class="xml_attribute_value">&quot;email&quot;</span><span class="xml_tag_symbols">&gt;&lt;</span><span class="xml_tag_name">string</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain">exo@localhost</span><span class="xml_tag_symbols">&lt;/</span><span class="xml_tag_name">string</span><span class="xml_tag_symbols">&gt;&lt;/</span><span class="xml_tag_name">field</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain"></span><br />
<span class="xml_plain">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="xml_tag_symbols">&lt;</span><span class="xml_tag_name">field</span><span class="xml_plain">&nbsp;</span><span class="xml_attribute_name">name</span><span class="xml_tag_symbols">=</span><span class="xml_attribute_value">&quot;groups&quot;</span><span class="xml_tag_symbols">&gt;&lt;</span><span class="xml_tag_name">string</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain">member:/africa</span><span class="xml_tag_symbols">&lt;/</span><span class="xml_tag_name">string</span><span class="xml_tag_symbols">&gt;&lt;/</span><span class="xml_tag_name">field</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain"></span><br />
<span class="xml_plain">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="xml_tag_symbols">&lt;/</span><span class="xml_tag_name">object</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain"></span><br />
<span class="xml_plain">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="xml_tag_symbols">&lt;/</span><span class="xml_tag_name">field</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain"></span><br />
<span class="xml_plain">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="xml_tag_symbols">&lt;</span><span class="xml_tag_name">field</span><span class="xml_plain">&nbsp;</span><span class="xml_attribute_name">name</span><span class="xml_tag_symbols">=</span><span class="xml_attribute_value">&quot;from&quot;</span><span class="xml_tag_symbols">&gt;&lt;</span><span class="xml_tag_name">string</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain">0</span><span class="xml_tag_symbols">&lt;/</span><span class="xml_tag_name">string</span><span class="xml_tag_symbols">&gt;&lt;/</span><span class="xml_tag_name">field</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain"></span><br />
<span class="xml_plain">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="xml_tag_symbols">&lt;</span><span class="xml_tag_name">field</span><span class="xml_plain">&nbsp;</span><span class="xml_attribute_name">name</span><span class="xml_tag_symbols">=</span><span class="xml_attribute_value">&quot;to&quot;</span><span class="xml_tag_symbols">&gt;&lt;</span><span class="xml_tag_name">string</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain">9</span><span class="xml_tag_symbols">&lt;/</span><span class="xml_tag_name">string</span><span class="xml_tag_symbols">&gt;&lt;/</span><span class="xml_tag_name">field</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain"></span><br />
<span class="xml_plain">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="xml_tag_symbols">&lt;/</span><span class="xml_tag_name">object</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain"></span><br />
<span class="xml_plain">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="xml_tag_symbols">&lt;/</span><span class="xml_tag_name">value</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain"></span><br />
<span class="xml_plain">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="xml_tag_symbols">&lt;/</span><span class="xml_tag_name">collection</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain"></span><br />
<span class="xml_plain">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="xml_tag_symbols">&lt;/</span><span class="xml_tag_name">field</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain"></span><br />
<span class="xml_plain">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="xml_tag_symbols">&lt;/</span><span class="xml_tag_name">object</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain"></span><br />
<span class="xml_plain">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="xml_tag_symbols">&lt;/</span><span class="xml_tag_name">object-param</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain"></span><br />
<span class="xml_plain">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="xml_tag_symbols">&lt;/</span><span class="xml_tag_name">init-params</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain"></span><br />
<span class="xml_plain">&nbsp;&nbsp;</span><span class="xml_tag_symbols">&lt;/</span><span class="xml_tag_name">component</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain">&nbsp;&nbsp;</span><br />
<span class="xml_tag_symbols">&lt;/</span><span class="xml_tag_name">configuration</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain"></span><br />

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

The code below illustrates the inclusion of all CSS resoucres for a new theme from the example file GateInResourcesCp060508/skin/MyPortalSkin/PortletThemes/Stylesheet.css.

/*---- 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;
}

It is recommended that users have some experience with CSS before studying GateIn 3.0 CSS.

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

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

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

To do so, every WAR deployed in can register the js files with the groovy script "WEB-INF/conf/script/groovy/JavascriptScript.groovy".

The example file below is found in the 01eXoResources.war

JavascriptService.addJavascript("eXo", "/javascript/eXo.js", ServletContext);
/* Animation Javascripts */
JavascriptService.addJavascript("eXo.animation.ImplodeExplode", "/javascript/eXo/animation/ImplodeExplode.js", ServletContext);
/* Application descriptor */
JavascriptService.addJavascript("eXo.application.ApplicationDescriptor", "/javascript/eXo/application/ApplicationDescriptor.js", ServletContext);
/* CORE Javascripts */
JavascriptService.addJavascript("eXo.core.Utils", "/javascript/eXo/core/Util.js", ServletContext);
JavascriptService.addJavascript("eXo.core.DOMUtil", "/javascript/eXo/core/DOMUtil.js", ServletContext);
JavascriptService.addJavascript("eXo.core.Browser", "/javascript/eXo/core/Browser.js", ServletContext);
JavascriptService.addJavascript("eXo.core.MouseEventManager", "/javascript/eXo/core/MouseEventManager.js", ServletContext);
JavascriptService.addJavascript("eXo.core.UIMaskLayer", "/javascript/eXo/core/UIMaskLayer.js", ServletContext);
JavascriptService.addJavascript("eXo.core.Skin", "/javascript/eXo/core/Skin.js", ServletContext);
JavascriptService.addJavascript("eXo.core.DragDrop", "/javascript/eXo/core/DragDrop.js", ServletContext);
JavascriptService.addJavascript("eXo.core.TemplateEngine", "/javascript/eXo/core/TemplateEngine.js", ServletContext);
/* Widget Javascripts */
JavascriptService.addJavascript("eXo.widget.UIWidget", "/javascript/eXo/widget/UIWidget.js", ServletContext);
JavascriptService.addJavascript("eXo.widget.UIAddWidget", "/javascript/eXo/widget/UIAddWidget.js", ServletContext);
JavascriptService.addJavascript("eXo.widget.UIExoWidget", "/javascript/eXo/widget/UIExoWidget.js", ServletContext);
/* Desktop Javascripts */
JavascriptService.addJavascript("eXo.desktop.UIDockbar", "/javascript/eXo/desktop/UIDockbar.js", ServletContext);
JavascriptService.addJavascript("eXo.desktop.UIDesktop", "/javascript/eXo/desktop/UIDesktop.js", ServletContext);
/* WebUI Javascripts */ 
JavascriptService.addJavascript("eXo.webui.UIItemSelector", "/javascript/eXo/webui/UIItemSelector.js", ServletContext);
JavascriptService.addJavascript("eXo.webui.UIForm", "/javascript/eXo/webui/UIForm.js", ServletContext);
JavascriptService.addJavascript("eXo.webui.UIPopup", "/javascript/eXo/webui/UIPopup.js", ServletContext);
JavascriptService.addJavascript("eXo.webui.UIPopupSelectCategory", "/javascript/eXo/webui/UIPopupSelectCategory.js", ServletContext);
JavascriptService.addJavascript("eXo.webui.UIPopupWindow", "/javascript/eXo/webui/UIPopupWindow.js", ServletContext);
JavascriptService.addJavascript("eXo.webui.UIVerticalScroller", "/javascript/eXo/webui/UIVerticalScroller.js", ServletContext);
JavascriptService.addJavascript("eXo.webui.UIHorizontalTabs", "/javascript/eXo/webui/UIHorizontalTabs.js", ServletContext);
JavascriptService.addJavascript("eXo.webui.UIPopupMenu", "/javascript/eXo/webui/UIPopupMenu.js", ServletContext);
JavascriptService.addJavascript("eXo.webui.UIDropDownControl", "/javascript/eXo/webui/UIDropDownControl.js", ServletContext);
/* Portal Javascripts */ 
JavascriptService.addJavascript("eXo.portal.PortalHttpRequest", "/javascript/eXo/portal/PortalHttpRequest.js", ServletContext);
JavascriptService.addJavascript("eXo.portal.UIPortal", "/javascript/eXo/portal/UIPortal.js", ServletContext);
JavascriptService.addJavascript("eXo.portal.UIWorkspace", "/javascript/eXo/portal/UIWorkspace.js", ServletContext);
JavascriptService.addJavascript("eXo.portal.UIPortalControl", "/javascript/eXo/portal/UIPortalControl.js", ServletContext);
JavascriptService.addJavascript("eXo.portal.PortalDragDrop", "/javascript/eXo/portal/PortalDragDrop.js", ServletContext);
JavascriptService.addJavascript("eXo.portal.UIPortalNavigation", "/javascript/eXo/portal/UIPortalNavigation.js", ServletContext);
JavascriptService.addJavascript("eXo.portal.UIMaskWorkspace", "/javascript/eXo/portal/UIMaskWorkspace.js", ServletContext);
JavascriptService.addJavascript("eXo.portal.UIExoStartMenu", "/javascript/eXo/portal/UIExoStartMenu.js", ServletContext);
/* Desktop Javascripts 2 */
JavascriptService.addJavascript("eXo.desktop.UIWindow", "/javascript/eXo/desktop/UIWindow.js", ServletContext);

Note that even registered dedicated javascripts will be merged into a single merged.js file when the server loads. This reduces the number of HTTP calls as seen in the home page 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.

To see or use the merged file set this property to 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 referenced with a module name of "eXo.core.DragDrop" which acts as a namespace. Inside the associated files, global javascript functions are used following the same namespace convention:

eXo.core.DragDrop = new DragDrop() ;

It is also possible to use the eXo.require() javascript method to lazy load and evaluate some javascript code. This is quite useful from the portlet or widget applications that will use this javascript only once. Otherwise, if the library is reusable in several places it is better to reference it in the groovy file.

Stuff Goes Here?

, as an integration and aggregation platform provides some form of Single Sign On (SSO).

When logging into the portal users gain access to many systems through portlets using a single identity. In many cases, however, the portal infrastructure must be integrated with other SSO enabled systems. There are many different Identity Management solutions available. In most cases each SSO framework provides a unique way to plug into a Java EE application.

In this tutorial, the SSO server is installed in a Tomcat installation. Tomcat can be obtained from http://tomcat.apache.org.

All the packages required for setup can be found in a zip file located at: http://repository.jboss.org/maven2/org/gatein/sso/sso-packaging

When manipulating gatein.ear directly it is better to not run any portal extensions that could override the data.

Remove $JBOSS_HOME/server/default/deploy/gatein-sample-extension.ear and $JBOSS_HOME/server/default/deploy/gatein-sample-portal.ear which are packaged by default with .

This Single Sign On plugin enables seamless integration between and the CAS Single Sign On Framework. Details about CAS can be found here.

The integration consists of two parts; the first part consists of installing or configuring a CAS server, the second part consists of setting up the portal to use the CAS server.

First we will set up the server to authenticate against the portal login module. You can find more information about setting up the server by reading the official CAS documentation, here we will install the CAS server on Tomcat

To simplify we will directly modify the sources so that the produced web archive is configured the way we want.

First we will want to change the authenticaton handler to use the portal authentication handler:

The CAS Server Plugin makes secure authentication callbacks to a RESTful service installed on the remote GateIn server in order to authenticate a user. In order for the plugin to function correctly, it needs to be properly configured to connect to this service. This configuration is done via the cas.war/WEB-INF/deployerConfigContext.xml file.

  1. Open $CAS_HOME/cas-server-webapp/src/main/webapp/WEB-INF/deployerConfigContext.xml

  2. Replace:

     <!--
      | Whereas CredentialsToPrincipalResolvers identify who it is some Credentials might authenticate, 
      | AuthenticationHandlers actually authenticate credentials.  Here e declare the AuthenticationHandlers that
      | authenticate the Principals that the CredentialsToPrincipalResolvers identified.  CAS will try these handlers in turn
      | until it finds one that both supports the Credentials presented and succeeds in authenticating.
      +-->
     <property name="authenticationHandlers">
       <list>
         <!--
          | This is the authentication handler that authenticates services by means of callback via SSL, thereby validating
          | a server side SSL certificate.
          +-->
         <bean class="org.jasig.cas.authentication.handler.support.HttpBasedServiceCredentialsAuthenticationHandler"
               p:httpClient-ref="httpClient" />
         <!--
          | This is the authentication handler declaration that every CAS deployer will need to change before deploying CAS 
          | into production.  The default SimpleTestUsernamePasswordAuthenticationHandler authenticates UsernamePasswordCredentials
          | where the username equals the password.  You will need to replace this with an AuthenticationHandler that implements your
          | local authentication strategy.  You might accomplish this by coding a new such handler and declaring
          | edu.someschool.its.cas.MySpecialHandler here, or you might use one of the handlers provided in the adaptors modules.
          +-->
         <bean
            class="org.jasig.cas.authentication.handler.support.SimpleTestUsernamePasswordAuthenticationHandler" />
       </list>
     </property>
    

  3. With the following (Make sure to set the host, port and context with the values corresponding to your portal). Also available in $GATEIN_SSO/cas/plugin/WEB-INF/deployerConfigContext.xml

    <!--
     | Whereas CredentialsToPrincipalResolvers identify who it is some Credentials might authenticate, 
     | AuthenticationHandlers actually authenticate credentials.  Here we declare the AuthenticationHandlers that
     | authenticate the Principals that the CredentialsToPrincipalResolvers identified.  CAS will try these handlers in turn
     | until it finds one that both supports the Credentials presented and succeeds in authenticating.
     +-->
     <property name="authenticationHandlers">
       <list>
         <!--
          | This is the authentication handler that authenticates services by means of callback via SSL, thereby validating
          | a server side SSL certificate.
          +-->
         <bean class="org.jasig.cas.authentication.handler.support.HttpBasedServiceCredentialsAuthenticationHandler"
               p:httpClient-ref="httpClient" />
         <!--
          | This is the authentication handler declaration that every CAS deployer will need to change before deploying CAS 
          | into production.  The default SimpleTestUsernamePasswordAuthenticationHandler authenticates UsernamePasswordCredentials
          | where the username equals the password.  You will need to replace this with an AuthenticationHandler that implements your
          | local authentication strategy.  You might accomplish this by coding a new such handler and declaring
          | edu.someschool.its.cas.MySpecialHandler here, or you might use one of the handlers provided in the adaptors modules.
          +-->
         <!-- Integrates with the Gatein Authentication Service to perform authentication -->
         <!--
          | Note: Modify the Plugin Configuration based on the actual information of a GateIn instance.
          | The instance can be anywhere on the internet...Not necessarily on localhost where CAS is running 
          +-->
         <bean class="org.gatein.sso.cas.plugin.AuthenticationPlugin">
            <property name="gateInHost"><value>localhost</value></property>
            <property name="gateInPort"><value>8080</value></property>
            <property name="gateInContext"><value>portal</value></property>
         </bean>
       </list>
     </property>
    

  4. Copy $GATEIN_SSO/cas/plugin/WEB-INF/lib/sso-cas-plugin-<VERSION>.jar and $GATEIN_SSO/cas/plugin/WEB-INF/lib/commons-httpclient-<VERSION>.jar into the newly created directory $CAS_HOME/cas-server-webapp/src/main/webapp/WEB-INF/lib

  5. Get an installation of Tomcat and extract it in what we will call $TOMCAT_HOME. Change the default port to avoid a conflict with the default GateIn (for testing purposes). Edit $TOMCAT_HOME/conf/server.xml and replace the 8080 port to 8888.

  6. Go to $CAS_HOME/cas-server-webapp and do 'mvn install'

  7. Copy $CAS_HOME/cas-server-webapp/target/cas.war into $TOMCAT_HOME/webapps

    Now you should be able to start Tomcat and access http://localhost:8888/cas but at this stage you won't be able to login.

This Single Sign On plugin enables seamless integration between GateIn Portal and the JOSSO Single Sign On Framework. Details about OpenSSO can be found here.

The integration consitsts in two parts, the first part consists of installing or configuring a JOSSO server, the second part consists of setting up the portal to use the JOSSO server.

This Single Sign On plugin enables seamless integration between GateIn Portal and the OpenSSO Single Sign On Framework. Details about OpenSSO can be found here.

The integration consitsts in two parts, the first part consists of installing or configuring an OpenSSO server, the second part consists of setting up the portal to use the OpenSSO server.

First we will set up the server to authenticate against the portal login module. You can find more information about setting up the server by reading the official OpenSSO documentation, here we will install the OpenSSO server on Tomcat

To simplify we will directly modify the sources so that the produced web archive is configured the way we want.

First we will want to add the GateIn Authentication Plugin:

The plugin makes secure authentication callbacks to a RESTful service installed on the remote GateIn server in order to authenticate a user. In order for the plugin to function correctly, it needs to be properly configured to connect to this service. This configuration is done via the opensso.war/config/auth/default/AuthenticationPlugin.xml file.

  1. Get an installation of Tomcat and extract it in what we will call $TOMCAT_HOME. Change the default port to avoid a conflict with the default GateIn (for testing purposes). Edit $TOMCAT_HOME/conf/server.xml and replace the 8080 port to 8888.

  2. This is what the $TOMCAT_HOME/webapps/opensso/config/auth/default/AuthenticationPlugin.xml file should look like:

    <?xml version='1.0' encoding="UTF-8"?>
    
    <!DOCTYPE ModuleProperties PUBLIC "=//iPlanet//Authentication Module Properties XML Interface 1.0 DTD//EN"
              "jar://com/sun/identity/authentication/Auth_Module_Properties.dtd">
    
    <ModuleProperties moduleName="AuthenticationPlugin" version="1.0" >
      <Callbacks length="2" order="1" timeout="60"
                 header="GateIn OpenSSO Login" >    
        <NameCallback>
          <Prompt>
    		Username
          </Prompt>
        </NameCallback>
        <PasswordCallback echoPassword="false" >
          <Prompt>
    		Password
          </Prompt>
        </PasswordCallback>
      </Callbacks>
    </ModuleProperties>
    

  3. Copy $GATEIN_SSO/opensso/plugin/WEB-INF/lib/sso-opensso-plugin-<VERSION>.jar , $GATEIN_SSO/opensso/plugin/WEB-INF/lib/commons-httpclient-<VERSION>.jar, and $GATEIN_SSO/opensso/plugin/WEB-INF/lib/commons-logging-<VERSION>.jar into the Tomcat Installation at: $TOMCAT_HOME/webapps/opensso/WEB-INF/lib

  4. Copy $GATEIN_SSO/opensso/plugin/WEB-INF/classes/gatein.properties into the Tomcat Installation at: $TOMCAT_HOME/webapps/opensso/WEB-INF/classes

  5. Now you should be able to start Tomcat and access http://localhost:8888/opensso/UI/Login?realm=gatein but at this stage you won't be able to login.

The servlet is the main entry point for incoming requests, it also includes some init code 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 into 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 nothing specific to 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 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 the case of a PortalRequestContext it is a direct delegate as the PortalRequestContext has a reference to the current UIPortalApplication.

In the 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.

All 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, so as to be loaded by the ClassLoader.

All resource files are in a subfolder named locale.

For instance; 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

Inside those file are 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 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.

For more information refer to: Section 5.4, “XML Resources Bundles”

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

The 02portal.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 (02portal.war:/WEB-INF/conf/common/locales-config.xml) contains the following code:

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

4

description Description for the language

5

description The default orientation of text and images is Left-To-Right. supports Right-To-Left orientation. Modifying text orientation is 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 are discussed in a later section.

2

init.resources TODO

3

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

These resources are merged to a single resource bundle which is accessible from anywhere in . 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 portlet internationalization.

The Inter Application Communication library is 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() { ... }

The service is defined by the class: org.exoplatform.upload.UploadService;

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 for a default upload size limit for the service to be configured. The 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 at 0 the upload size is unlimited.

Procedure 5.2. How to use the upload component

  1. Create an object type org.exoplatform.webui.form.UIFormUploadInput.

    Two constructors are available for this:

    public UIFormUploadInput(String name, String bindingExpression)
    

    or:

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

    This 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);
  2. To obtain the limit from the xml configuration, this piece of code can be added to the either portlet.xml or portlet-preferences.xml :

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

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

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

    UIFormUploadInput input = (UIFormUploadInput)uiForm.getUIInput("upload");
    
    InputStream inputStream = input.getUploadDataAsStream();
    ...
    jcrData.setValue(inputStream);
  4. The upload service stores a temporary file on the filesystem during the upload process. When the upload is finished, the service must be cleaned in order to:

    1. Delete the temporary file.

    2. Delete the classes used for the upload.

    Use theremoveUpload() method defined in the upload service to purge the file:

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

    Saving the uploaded file

    Ensure the file is saved before the service is cleaned.

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

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

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

    Example : ParentClass is the class being wrtitten in.

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

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

    For example; the configuration below is for UIAccountForm:

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

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

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

    Possible ways to use the event attribute :

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

    event.getRequestContext().addUIComponentToUpdateByAjax(uicomponent);
    

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

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

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

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

In this class, there are four functions/classes:

PortletResponse

PortalResponse

AjaxRequest

HttpResponseHandler

and 6 functions:

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

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

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

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

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

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

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

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

Use the following steps to create a new template;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

In the PortletApplication, the line;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Maven

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

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

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

package org.gatein.portal.examples.portlets;


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

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

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

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

2

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

3

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

4

Write the markup to display.

5

Closing the writer.

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

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

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

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

2

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

3

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

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

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

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

4

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

This section discusses:

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

package org.gatein.portal.examples.portlets;


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

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

2

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

3

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

4

Perform the inclusion of the markup obtained from the JSP.

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

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

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

...

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

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

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

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

...

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

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

2

Here the parameter is retrieved through an action URL .

3

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

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


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

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

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

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

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

<br/>

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

<br/>

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

<br/>

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

<br/>

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

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

The portlet taglib, needs to be declared.

2

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

3

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

4

The variable myRenderURL is used like any other JSP variable.

5

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

6

The action URL is used in HTML form.

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

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

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

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


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

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

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

In WEB-INF, create file portlet.xml :


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

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

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

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

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

package testRomain.portlet.component;

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

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

public UITestRomainPortlet() throws Exception {

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

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

<% uicomponent.renderChildren(); %>

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

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

public static class OpenPopupActionListener extends EventListener<UITestRomainPortlet> {

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

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

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

A gadget is a mini web application, embedded in a web page and running on an application server platform. These small applications help users perform various tasks.

supports gadgets such as: Todo gadget, Calendar gadget, Calculator gadget, Weather Forecasts and and RSS Reader.

Important

The following sections require more textual information.