JBoss.orgCommunity Documentation

Chapter 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. Portal.xml
2.3.4. Navigation.xml
2.3.5. Pages.xml
2.3.6. Portlet-preferences.xml
2.3.7. Group Navigation
2.3.8. User Navigation
2.3.9. 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. DB and datasource configuration
2.6.3. JCR database configuration
2.7. Data Injector Configuration
2.7.1. Data Injector
2.7.2. OrganizationInitializer
2.7.3. Service configuration file
2.7.4. Parameters for Group
2.7.5. Parameters for User
2.8. Skin Configuration
2.8.1. Overview
2.8.2. Skin Switching
2.8.3. Skins in Page Markups
2.8.4. Types of Styles
2.8.5. Portlet Styles
2.8.6. How to Configure a Portal Skin
2.8.7. Tips and Tricks
2.8.8. How to create a new skin
2.8.9. How to create new themes
2.9. Javascript Configuration
2.10. Dashboard configuration
2.10.1. Parameters (in edit mode)
2.11. Authentication Token Configuration
2.11.1. Overview
2.11.2. What is token service
2.11.3. Implement token service's API
2.11.4. Configure token services

GateIn by default uses PicketLink IDM component to persist identity information (user, groups, memberships and etc.). While still legacy exo interfaces are used (org.exoplatform.services.organization) for identity management the wrapper implementation delegates to the PicketLink IDM framework. This section won't provide information about PicketLink IDM and its configuration - please refer to proper project documentation (http://jboss.org/picketlink/IDM.html). It is important to fully understand concepts behind this framework design before changing configuration

Identity model represented in 'org.exoplatform.services.organization' interfaces and one used in JBoss Identity IDM have some major differences. JBoss Identity IDM provides greater abstraction - for example it is possible for groups in IDM framework to form memberships with many parents while GateIn model allows only pure tree like membership structures - this requires recursive ID translation. Additionally GateIn membership concept needs to be translated into IDM Role concept. Therefore JBoss Identity IDM model is used in a limited way. All those translations are applied by the integration layer

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

   <component>
      <key>org.exoplatform.services.organization.jbidm.JBossIDMService</key>
      <type>org.exoplatform.services.organization.jbidm.JBossIDMServiceImpl</type>
      <init-params>
         <value-param>
            <name>config</name>
            <value>war:/conf/organization/idm-config.xml</value>
         </value-param>
         <values-param>
            <name>hibernate.annotations</name>
            <value>org.jboss.identity.idm.impl.model.hibernate.HibernateIdentityObject</value>
            <value>org.jboss.identity.idm.impl.model.hibernate.HibernateIdentityObjectAttribute</value>
            <value>org.jboss.identity.idm.impl.model.hibernate.HibernateIdentityObjectBinaryAttribute</value>
            <value>org.jboss.identity.idm.impl.model.hibernate.HibernateIdentityObjectBinaryAttributeValue</value>
            <value>org.jboss.identity.idm.impl.model.hibernate.HibernateIdentityObjectCredential</value>
            <value>org.jboss.identity.idm.impl.model.hibernate.HibernateIdentityObjectCredentialType</value>
            <value>org.jboss.identity.idm.impl.model.hibernate.HibernateIdentityObjectRelationship</value>
            <value>org.jboss.identity.idm.impl.model.hibernate.HibernateIdentityObjectRelationshipName</value>
            <value>org.jboss.identity.idm.impl.model.hibernate.HibernateIdentityObjectRelationshipType</value>
            <value>org.jboss.identity.idm.impl.model.hibernate.HibernateIdentityObjectTextAttribute</value>
            <value>org.jboss.identity.idm.impl.model.hibernate.HibernateIdentityObjectType</value>
            <value>org.jboss.identity.idm.impl.model.hibernate.HibernateRealm</value>
         </values-param>
         <properties-param>
            <name>hibernate.properties</name>
            <property name="hibernate.hbm2ddl.auto" value="update"/>
            <property name="hibernate.current_session_context_class" value="thread"/>
            <property name="hibernate.show_sql" value="false"/>
            <property name="hibernate.cglib.use_reflection_optimizer" value="true"/>
            <property name="hibernate.connection.url" value="jdbc:hsqldb:file:../temp/data/exodb${container.name.suffix}"/>
            <property name="hibernate.connection.driver_class" value="org.hsqldb.jdbcDriver"/>
            <property name="hibernate.connection.autocommit" value="true"/>
            <property name="hibernate.connection.username" value="sa"/>
            <property name="hibernate.connection.password" value=""/>
            <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/>
            <property name="hibernate.c3p0.min_size" value="5"/>
            <property name="hibernate.c3p0.max_size" value="20"/>
            <property name="hibernate.c3p0.timeout" value="1800"/>
            <property name="hibernate.c3p0.max_statements" value="50"/>
            <property name="hibernate.connection.provider_class" value="org.hibernate.connection.C3P0ConnectionProvider" />
         </properties-param>

      </init-params>
   </component>

   <component>
      <key>org.exoplatform.services.organization.OrganizationService</key>
      <type>org.exoplatform.services.organization.jbidm.JBossIDMOrganizationServiceImpl</type>
   </component>

</configuration>

org.exoplatform.services.organization.jbidm.JBossIDMOrganizationServiceImpl is a main entrypoint implementing org.exoplatform.services.organization.OrganizationService and is dependant on org.exoplatform.services.organization.jbidm.JBossIDMService

org.exoplatform.services.organization.jbidm.JBossIDMServiceImpl service has following options:

org.exoplatform.services.organization.jbidm.JBossIDMOrganizationServiceImpl service has following options:

Additionally JBossIDMOrganizationServiceImpl uses those defaults to perform identity management operations

Sample JBoss Identity IDM configuration file is shown below. To understand all options present in it please refer to the JBoss Identity 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>

When a user logs in he sees three types of navigation tree:

they all are configured thanks to the usual XML configuration syntax in a 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>

In the previous XML file we define, for the 3 navigation types, some sets of predefined portal, groups or users that will have some XML files inside the 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 hence only modifiable from the portal UI.

That file describes the layout and portlets that will be shown for all pages. Usually the layout contains the banner, footer, menu, breadcrumbs portlets. Indeed, in GateIn, every area is a portlet even the banner and footer which makes the platform extremely configurable.


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

Even if not shown in the previous XML file, it is also possible to apply a nested container that can also contain portlets. Containers are then responsible of the layout of their children (row, column or tabs containers exist).

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

In order to define at which location GateIn Portal shall render the current page use the page-body tag.

The defined classic portal is accessible to "Everyone" (that means it can be accessed through the URL /portal/public/classic) but only members of the group /platform/administrators can edit it.

This XML file structure is very similar to portal.xml and it can also contain container tags. Each application can decide if it wishes 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>

Porlet instances can be associated with portlet-preferences that override the one defined in the usual 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 is owned by a user. You can see that part as the user dashboard. The files needed are navigation.xml, pages.xml, portlet-preferences.xml. You will also find gadgets.xml (formerly called widgets.xml) which defines the gadgets (widgets) that will be located in the user workspace. The user workspace is located at the left hand side, the access is restricted to some privileged users, see Section 2.4, “Predefined User Configuration”

Those files are located in the directory "portal/WEB-INF/conf/portal/users/{userName}"


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

Note that when you develop a portal, we advise you to use the XML instead of the User Interface as XML will allow you to provide a preconfigured package to your customer. But as each time you start the server the first time, the XML files are stored in the JCR, it will be necessary to remove the database (the jcr leverages a database). During the development phase using tomcat it simply means to delete the directory: exo-tomcat/temp

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>

You can find the database configuration in the portal/WEB-INF/conf/database/database-configuration.xml file (located in your application server's web application directory).


<?xml version="1.0" encoding="ISO-8859-1"?>
<configuration>
  [...]
  <component>
    <key>org.exoplatform.services.database.HibernateService</key>
    <jmx-name>database:type=HibernateService</jmx-name>
    <type>org.exoplatform.services.database.impl.HibernateServiceImpl</type>
    <init-params>
      <properties-param>
        <name>hibernate.properties</name>
        <description>Default Hibernate Service</description>
        <property name="hibernate.show_sql" value="false"/>
        <property name="hibernate.cglib.use_reflection_optimizer" value="true"/>
        <property name="hibernate.connection.url" value="jdbc:hsqldb:file:../temp/data/exodb"/>
        <property name="hibernate.connection.driver_class" value="org.hsqldb.jdbcDriver"/>
        <property name="hibernate.connection.autocommit" value="true"/>
        <property name="hibernate.connection.username" value="sa"/>
        <property name="hibernate.connection.password" value=""/>
        <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/>
        <property name="hibernate.c3p0.min_size" value="5"/>
        <property name="hibernate.c3p0.max_size" value="20"/>
        <property name="hibernate.c3p0.timeout" value="1800"/>
        <property name="hibernate.c3p0.max_statements" value="50"/>
      </properties-param>
    </init-params>
  </component>
  <external-component-plugins>
    <target-component>org.exoplatform.services.naming.InitialContextInitializer</target-component>
    <component-plugin>
      <name>bind.datasource</name>
      <set-method>addPlugin</set-method>
      <type>org.exoplatform.services.naming.BindReferencePlugin</type>
      <init-params>
        <value-param>
          <name>bind-name</name>
          <value>jdbcexo</value>
        </value-param>
        <value-param>
          <name>class-name</name>
          <value>javax.sql.DataSource</value>
        </value-param>
        <value-param>
          <name>factory</name>
          <value>org.apache.commons.dbcp.BasicDataSourceFactory</value>
        </value-param>
        <properties-param>
          <name>ref-addresses</name>
          <description>ref-addresses</description>
          <property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
          <property name="url" value="jdbc:hsqldb:file:../temp/data/exodb"/>
          <property name="username" value="sa"/>
          <property name="password" value=""/>
        </properties-param>
      </init-params>
    </component-plugin>
  </external-component-plugins>
  [...]
</configuration>

The first component configuration is for the Hibernate service. You can enter any additional properties in a hibernate.properties file, but GateIn will override hibernate.properties with values read in from this configuration file.

The second component configuration is for the JCR datasource. The InitialContextInitializer component will load the factory class, use the factory object to create a datasource, and bind that datasource in the JNDI tree with the value of the "bind-name" parameter. If you want to change the bind-name, for example "jdbcexo" to "myjdbc", you also need to change JCR repository configuration in order that the service picks up the right datasource.

Make sure you update the database connection properties and dialect for both of these component configurations.

There are two JCR configuration files that must be changed to support a different database. In both files, edit the dialect (and the data source name if necessary) .

The first file is 02portal.war:/WEB-INF/conf/jcr/jcr-configuration.xml :

[...]
 <component>
   <key>org.exoplatform.services.jcr.config.RepositoryServiceConfiguration</key>
   <type>org.exoplatform.services.jcr.impl.config.RepositoryServiceConfigurationImpl</type>
   <init-params>
     <value-param>
       <name>conf-path</name>
       <description>JCR configuration file</description>
       <value>war:/conf/jcr/repository-configuration.xml</value>
     </value-param>
     <properties-param>
       <name>working-conf</name>
       <description>working-conf</description>
       <property name="persisterClassName" value="org.exoplatform.services.jcr.impl.config.JDBCConfigurationPersister"/>
       <property name="sourceName" value="jdbcexo"/>
       <property name="dialect" value="hsqldb"/>
     </properties-param>
   </init-params>
 </component>
[...]

The second file is 02portal.war:/WEB-INF/conf/jcr/repository-configuration.xml :


 ...]     
     <workspaces>
       <workspace name="system" auto-init-root-nodetype="nt:unstructured" 
                  auto-init-permissions="*:/platform/administrators read;*:/platform/administrators add_node;*:/platform/administrators set_property;*:/platform/administrators remove" >
          <!-- for system storage -->
          <container class="org.exoplatform.services.jcr.impl.storage.jdbc.JDBCWorkspaceDataContainer">
            <properties>
              <property name="sourceName" value="jdbcexo"/>
              <property name="dialect" value="hsql"/>
              <!-- property name="db-type" value="mysql"/ -->
              <property name="multi-db" value="false"/>
              <property name="update-storage" value="true"/>
              <property name="max-buffer-size" value="204800"/>
              <property name="swap-directory" value="../temp/swap/system"/>
            </properties>
[...]
       </workspace>
       <workspace name="collaboration" auto-init-root-nodetype="nt:unstructured" 
                  auto-init-permissions="any read;*:/platform/administrators read;*:/platform/administrators add_node;*:/platform/administrators set_property;*:/platform/administrators remove" >
          <!-- for system storage -->
          <container class="org.exoplatform.services.jcr.impl.storage.jdbc.JDBCWorkspaceDataContainer">
            <properties>
              <property name="sourceName" value="jdbcexo"/>
              <property name="dialect" value="hsqldb"/>
              <property name="multi-db" value="false"/>
              <property name="update-storage" value="true"/>
              <property name="max-buffer-size" value="204800"/>
              <property name="swap-directory" value="../temp/swap/collaboration"/>
            </properties>
[...]
       </workspace>
       <workspace name="backup" auto-init-root-nodetype="nt:unstructured" 
                  auto-init-permissions="any read;*:/platform/administrators read;*:/platform/administrators add_node;*:/platform/administrators set_property;*:/platform/administrators remove" >
          <!-- for system storage -->
          <container class="org.exoplatform.services.jcr.impl.storage.jdbc.JDBCWorkspaceDataContainer">
            <properties>
              <property name="sourceName" value="jdbcexo"/>
              <property name="dialect" value="mysql"/>
              <!-- property name="db-type" value="mysql"/ -->
              <property name="multi-db" value="false"/>
              <property name="update-storage" value="true"/>
              <property name="max-buffer-size" value="204800"/>
              <property name="swap-directory" value="../temp/swap/backup"/>
            </properties>
       </workspace>
[...]
      </workspaces>
[...]

<configuration>
  <component>
  <key>org.exoplatform.portal.initializer.organization.OrganizationInitializer</key>
  <type>org.exoplatform.portal.initializer.organization.OrganizationInitializer</type>
    <init-params>
      <value-param>
        <name>auto.create.group.page.navigation</name>
        <description>true or false</description>
        <value>true</value>
      </value-param>
       
      <value-param>
        <name>auto.create.user.page.navigation</name>
        <description>number of pages per user</description>
        <value>10</value>
      </value-param>
      
      <object-param>
        <name>organization</name>
        <description>description</description>
        <object type="org.exoplatform.portal.initializer.organization.OrganizationConfig">
          <field name="groups">
            <collection type="java.util.ArrayList">
              <value>
                <object type="org.exoplatform.portal.initializer.organization.OrganizationConfig$GroupsConfig">
                  <field name="group">
                    <object type="org.exoplatform.services.organization.OrganizationConfig$Group">
                      <field name="name"><string>province</string></field>
                      <field name="parentId"><string>/africa/tanzania</string></field>
                      <field name="description"><string>Tanzania's province</string></field>
                      <field name="label"><string>Province</string></field>
                    </object>                
                  </field> 
                  <field name="from"><string>1</string></field>
                  <field name="to"><string>10</string></field>
                </object>
              </value>
            </collection>
          </field>
          <field name="users">
            <collection type="java.util.ArrayList"> 
              <value>
                <object type="org.exoplatform.portal.initializer.organization.OrganizationConfig$UsersConfig">
                  <field name="user">
                    <object type="org.exoplatform.services.organization.OrganizationConfig$User">
                      <field name="userName"><string>user</string></field>
                      <field name="password"><string>GateInPlatform</string></field>
                      <field name="firstName"><string>First-Name</string></field>
                      <field name="lastName"><string>Last-Name</string></field>
                      <field name="email"><string>exo@localhost</string></field>
                      <field name="groups"><string>member:/africa</string></field>
                    </object>
                  </field>
                  <field name="from"><string>0</string></field>
                  <field name="to"><string>9</string></field>
                </object>
              </value>
            </collection>
          </field>
        </object>
      </object-param>
    </init-params>
  </component>  
</configuration>

The SkinService is an GateIn service that manages portal skin, portlet styles and portlet themes (windows borders). The code snippet below is an excerpt of the API offered by this service.

/**

   * Register the stylesheet for a portal Skin.
   * @param module skin module identifier
   * @param skinName skin name
   * @param cssPath path uri to the css file. This is relative to the root context, use leading '/'
   * @param scontext the webapp's {@link ServletContext}
   */
  public void addPortalSkin(String module, String skinName, String cssPath, ServletContext scontext) {
    [...]
  }
  /**
   * Register a portlet stylesheet for a Skin.
   * @param module skin module. Typically of the form 'portletAppName/portletName' .
   * @param skinName Name of the skin
   * @param cssPath path uri to the css file. This is relative to the root context, use leading '/'
   * @param scontext the webapp's {@link ServletContext}
   */
  public void addSkin(String module, String skinName, String cssPath, ServletContext scontext) {
    [...]
  }
  /**
   * Get a skin configuration for a given Skin
   * @param module skin module such as registered in {@link #addSkin(String, String, String, ServletContext)}
   * @param skinName skin name
   * @return the skin configuration or, if not found try to find the default skin
   */
  public SkinConfig getSkin(String module, String skinName) {
    [...]
  }
  /**
   * Register multiple portlet themes
   * @param categoryName portlet theme category
   * @param themesName names of the themes
   */
  public void addTheme(String categoryName, List<String> themesName) {
    [...]
  }

Use the skin service to register your own portal skins, portlet styles and portlet themes.

The SkinListener looks for the groovy script file located in your war under: /WEB-INF/conf/script/groovy/SkinConfigScript.groovy

In this script, you have full access to the SkinService and ServletContext which are bound as scripting variables under the same name. As an example, take a look at the following script. It can be found in the GateInResources.war and is used by GateIn to register the Default portal skin and some portlet themes.

SkinService.addPortalSkin("CoreSkin","Default", "/GateInResources/skin/Stylesheet.css", ServletContext);
SkinService.addTheme("Simple", ["SimpleBlue","SimpleViolet","SimpleOrange","SimplePink","SimpleGreen"]);
SkinService.addTheme("RoundConer", ["RoundConerBlue","RoundConerViolet","RoundConerOrange","RoundConerPink","RoundConerGreen"]);
SkinService.addTheme("Shadow", ["ShadowBlue","ShadowViolet","ShadowOrange","ShadowPink","ShadowGreen"]);
SkinService.addTheme("MacStyle", ["MacTheme","MacGray","MacGreenSteel","MacBlack"]);
SkinService.addTheme("VistaStyle", ["VistaTheme","VistaBlue"]);

The syntax of addTheme() is:

addTheme(String categoryName, List<String> themesName)

So, to provide your own skin you could use the following:

SkinService.addSkin("mywebapp/MyPortlet", "MyPortalSkin", "/mywebapp/skin/Stylesheet.css", ServletContext);

This simple line would register a styleesheet for a portlet named MyPortlet in a portlet app named mywebapp. The stylesheet would be used when a skin named MyPortalSkin is selected in portal.

The syntax of addSkin() is:

addSkin(String module, String skinName, String cssPath, ServletContext scontext, boolean overwrite)

overwrite is optional, its default value is "false". If its value is true, the later call of addSkin() for the same skin key (combination of module + skinName) replaces the skin of the previous call.

Similarly, to configure a particular portal you can use the following :

SkinService.addSkin("myportalname", "skin", "/path/to/skin/Stylesheet.css", ServletContext);

The syntax of addPortalSkin() is:

addPortalSkin(String module, String skinName, String cssPath, ServletContext scontext, boolean overwrite)

Before studying GateIn CSS, make sure you already have some experience with css and read the css spec at http://www.w3.org/TR/REC-CSS2/selector.html

GateIn relies heavily on CSS to create the layout and special effects for the UI. Below we explain some common techniques you may find often inside GateIn's markup. We explain them here to help you better understand GateIn generated markup, ease css issues fixing or get inspration for styling your own apps.

New skin can be created by the configuration. Firstly, you have to definy the new skin in WEB-INF/conf/script/groovy/SkinConfigScript.groovy in your Ressource (for example, in the project MyPortal, you can put it in GateInResourcesMyPortal).

SkinService.addPortalSkin("MyPortalSkin","MyPortal","/GateInResourcesMyPortal/skin/Stylesheet.css",ServletContext);

Secondly, you put all your new skin into folder skinyourSkin and create new file Stylesheet.css here. In this file, you will import all links to your CSS. For example in MyPortal project.

@import url(MyPortalSkin/portal/webui/component/UIPortalApplicationSkin.css) ;
@import url(MyPortalSkin/webui/component/Stylesheet.css) ;

Finally, you have to definy the name of new skin and the image preview for the Skin Settings action in "User Workspace" .

By default, if you don not set new name for skin, its name is label>. Looking in the file and add yout new name here.

#############################################################################
#                              Change Skin                                  #
#############################################################################
  
UIChangeSkin.action.save=Appliquer
UIChangeSkin.action.close=Fermer
UIChangeSkin.title.SkinSetting=Configuration des styles
UIChangeSkin.MyPortal.label=Style MyPortal
UIChangeSkin.Default.label=Style par d?faut
UIChangeSkin.Mac.label=Style Mac
UIChangeSkin.Vista.label=Style Vista
Skin.title=Liste des styles
Skin.left.title=Voir et s?lectionner un style

The image peeview can be set in file ressource/skin/DefaultSkin/portal/webui/component/customization/UIChangeSkinForm/Stylesheet.css of Portal.

.UIChangeSkinForm .UIItemSelector .TemplateContainer .MyPortalImage {
	margin: auto;
	width: 329px; height:204px;
	background: url('background/MyPortal.jpg') no-repeat top;
	cursor: pointer ;
}

And now, you copy your image MyPortal.jpg (that you defined above) to the folder ressource/skin/DefaultSkin/portal/webui/component/customization/UIChangeSkinForm/background and test your new skin.

Firstly, you have to definy the new theme in WEB-INF/conf/script/groovy/SkinConfigScript.groovy in your Ressource (for example, in the project MyPortal, you can put it in GateInResourcesCp060508).

SkinService.addTheme("MyPortal-MacTheme", ["MacGray","MacBlue","MacBlack"]);

Secondly, you put all your new theme into folder skinyourSkin and create new file Stylesheet.css here. In this file, you will import all links to your CSS. For example in MyPortal project.

@import url(MyPortalSkin/PortletThemes/Stylesheet.css) ;

You can see here, in the GateInResourcesCp060508/skin/MyPortalSkin/PortletThemes/Stylesheet.css, you put all your CSS of new theme.

/*---- MyPortalTheme ----*/
.MyPortalTheme .WindowBarCenter .WindowPortletInfo {
	margin-right: 80px; /* orientation=lt */
	margin-left: 80px; /* orientation=rt */
}
.MyPortalTheme .WindowBarCenter .ControlIcon {
	float: right;/* orientation=lt */
	float: left;/* orientation=rt */
	width: 24px; 
	height: 17px;
	cursor: pointer;
	background-image: url('background/MyPortalTheme.png');
}
.MyPortalTheme .ArrowDownIcon {
	background-position: center 20px;
}
.MyPortalTheme .OverArrowDownIcon {
	background-position: center 116px;
}
.MyPortalTheme .MinimizedIcon {
	background-position: center 44px;
}
.MyPortalTheme .OverMinimizedIcon {
	background-position: center 140px;
}
.MyPortalTheme .MaximizedIcon {
	background-position: center 68px;
}
.MyPortalTheme .OverMaximizedIcon {
	background-position: center 164px;
}
.MyPortalTheme .RestoreIcon {
	background-position: center 92px;
}
.MyPortalTheme .OverRestoreIcon {
	background-position: center 188px;
}
.MyPortalTheme .NormalIcon {
	background-position: center 92px;
}
.MyPortalTheme .OverNormalIcon {
	background-position: center 188px;
}
.UIPageDesktop .MyPortalTheme .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 */
}
.MyPortalTheme .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 */
}
.MyPortalTheme .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;
}
.MyPortalTheme .WindowBarCenter .PortletName {
	font-weight: bold;
	color: #333333;
	overflow: hidden;
	white-space: nowrap;
	width: 100%;
}
.MyPortalTheme .WindowBarLeft {
	padding-left: 12px;
	background-image: url('background/MyPortalTheme.png');
	background-repeat: no-repeat;
	background-position: left -148px;
}
.MyPortalTheme .WindowBarRight {
	padding-right: 11px;
	background-image: url('background/MyPortalTheme.png');
	background-repeat: no-repeat;
	background-position: right -119px;
}
.MyPortalTheme .WindowBarCenter {
	background-image: url('background/MyPortalTheme.png');
	background-repeat: repeat-x;
	background-position: left -90px;
}
.MyPortalTheme .WindowBarCenter .FixHeight {
	height: 21px;
	padding-top: 8px;
}
.MyPortalTheme .MiddleDecoratorLeft {
	padding-left: 12px;
	background: url('background/MMyPortalTheme.png') repeat-y left;
}
.MyPortalTheme .MiddleDecoratorRight {
	padding-right: 11px;
	background: url('background/MMyPortalTheme.png') repeat-y right;
}
.MyPortalTheme .MiddleDecoratorCenter {
	background: #ffffff;
}
.MyPortalTheme .BottomDecoratorLeft {
	padding-left: 12px;
	background-image: url('background/MyPortalTheme.png');
	background-repeat: no-repeat;
	background-position: left -60px;
}
.MyPortalTheme .BottomDecoratorRight {
	padding-right: 11px;
	background-image: url('background/MyPortalTheme.png');
	background-repeat: no-repeat;
	background-position: right -30px;
}
.MyPortalTheme .BottomDecoratorCenter {
	background-image: url('background/MyPortalTheme.png');
	background-repeat: repeat-x;
	background-position: left top;
}
.MyPortalTheme .BottomDecoratorCenter .FixHeight {
	height: 30px;
}

Manaing Javascript scripts in an application like GateIn Platform is a critical part of the configuration work if you want to get good response time.

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, GateIn 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 GateIn can register the js files thanks to a groovy script "WEB-INF/conf/script/groovy/JavascriptScript.groovy". The next file is the one you can find in the GateInResources.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 if the you register dedicated javascripts, they will be merged into a single merged.js file when the server will load in order to reduce 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, you may find it easier to deactivate this optimization while debugging your javascript. For that, you simply need to set the java system property exo.product.developing to true. But if you want to see or use the merged file you have to set this property to false. You can pass the property 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 type "eXo.core.DragDrop" which acts like 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.