Chapter 1. AIO Migration Guide

Preamble
Prerequisites
Questions to ask
Prepare your extension project
Prepare eXo XML customizations
Portal Migration
Portal declarations
Portal metadata descriptors
Resource Bundles
ApplicationRegistry service configurations
API changes
Custom portlets migration
ECM Migration
ECM portlets
ECM actions
ECM drives
Publication lifecycle
ECM APIs changes
ECM templates migration
ECM UI extension migrations
Graphic Chart Migration
Changes in web.xml of webapps
new deployment descriptor : gatein-resource.xml
Javascripts
CSS
Organization Data Model Migration
Data Migration
Server Environment Migration
Data sources

This guide helps you migrate your project from eXo All In One 1.6 to eXo Platform 3.0.

You need to create a brand new project and migrate your old one into it. Platform introduced a new way to package your project customization called extensions. By using WAR extension configuration approach, you can overload Platform's default files defined in WARs, such as gtmpl, favicon, xml, jsp files. If you do not understand what that means, get back to Developers Guide to learn how to bootstrap the basic structure for your extension project.

The extension mechanism allows loading .xml configuration files from your extension war. Previously, you had to wire the loading of your xml configurations through the external configuration directory via import statements. Now, you can place all your .xml files in your extension webapp. eXo Platform will read and load from your WEB-INF/conf/configuration.xml.

Read more on this in the Developers Guide.

Tip

In most cases, you do not even need to do it. But if you are still tempted to alter an .xml file of the portal.war, that is simple : don't do it! The extension mechanism lets you virtually override any file from portal.war by placing a file in your extension at the exact same location. For example, to override portal.war!WEB-INF/conf/database/configuration.xml, simply place a your file in myextension.war!WEB-INF/conf/database/configuration.xml.

Note

Be careful about the files shifting to the WAR extension, use war: prefix to redefine the moved Metadata & Gtmpl files, such as:

  • CLV Templates

  • Locales config file definition

  • Repository configuration

  • NodeTypes Templates

  • Gtmpl files

Although it is not strictly required, you are recommended to use Apache Maven 2.2 to build your project. You will benefit of the eXo maven repository for all eXo libraries and their dependencies.

ECM dependencies have changed significantly. The table below helps you match old and new Maven artifacts :

AIO Platform

<dependency>
  <groupId>org.exoplatform.ecm.dms.core</groupId>
   <!-- any artifact -->
  <artifactId>*</artifactId>
  <version>${org.exoplatform.ecm.dms.version}</version>
  <scope>provided</scope>
</dependency>

<dependency>
  <groupId>org.exoplatform.ecms</groupId>
  <artifactId>exo-ecms-core-services</artifactId>
  <version>${org.exoplatform.ecms.version}</version>
  <scope>provided</scope>
</dependency>

<dependency>
  <groupId>org.exoplatform.ecm.dms.core</groupId>
  <artifactId>exo.ecm.dms.core.webui.ext</artifactId>
  <version>${org.exoplatform.ecm.dms.version}</version>
  <scope>provided</scope>
</dependency>

<dependency>
  <groupId>org.exoplatform.ecms</groupId>
  <artifactId>exo-ecms-core-webui</artifactId>
  <version>${org.exoplatform.ecms.version}</version>
  <scope>provided</scope>
</dependency>

<dependency>
  <groupId>org.exoplatform.ecm.dms.core</groupId>
  <artifactId>exo.ecm.dms.core.portlet.ecm.core.main</artifactId>
  <version>${org.exoplatform.ecm.dms.version}</version>
  <scope>provided</scope>
</dependency>

<dependency>
  <groupId>org.exoplatform.ecms</groupId>
  <artifactId>exo-ecms-core-webui-explorer</artifactId>
  <version>${org.exoplatform.ecms.version}</version>
  <scope>provided</scope>
</dependency>

In AIO, ECM was composed of 3 modules with a separate lifecycle (DMS, WCM and Workflow) and each artifact had a different version. In Platform, the ECM subsystem is now called eXo Content and the 3 modules follow the same lifecycle. So their artifacts hold the same version.

So, if your AIO project had defined properties like org.exoplatform.ecm.dms.version or org.exoplatform.ecm.wcm.version, replace them by org.exoplatform.ecms.version.

As you know, most of the customization in AIO is done via .xml files. It is still the case in Platform, but they have evolved. The list of available components and plugins has changed, and the .xml files layout has also evolved.

Customizing pages and navigations is done by the component named org.exoplatform.portal.config.UserPortalConfigService.

In AIO, you have to redefine the component entirely. In Platform, there is now an external-component-plugin, that you can call from your extension in order to add your own customizations. See this chapter for further information.

Transform your component declaration into an external-component-plugin declaration:

AIO Platform

<component>
	<key>org.exoplatform.portal.config.UserPortalConfigService</key>
	<type>org.exoplatform.portal.config.UserPortalConfigService</type> 
	...
		<value-param>
			<name>default.portal</name>
			<description>The default portal</description>
			<value>defaultPortalName</value>
		</value-param>
	...
</component>

<external-component-plugins>
	<target-component>org.exoplatform.portal.config.UserPortalConfigService</target-component>
	... (same thing)
		<!-- If you define a new "default.portal" value in your extension,
		it will be considered as prior to any other "default.portal" definition -->
		<value-param>
			<name>default.portal</name>
			<description>The default portal</description>
			<value>defaultPortalName</value>
		</value-param> 
	... (same thing)
</external-component-plugins>

Use Migration Tools (see, the Migration Tools Guide, section Portal Configuration Migration ) to automatically export and convert AIO Portal metadata descriptors. The following paragraphs describe more about what was changed in Platform Portal metadata descriptors:

The navigation.xml file contains the navigations of your portal. In AIO, a node could be visible or invisible. GateIn has extended the concept of visibility. AIO's visibility maps as follow in Platform :

AIO Platform

<visible>false</visible>

<visibility>HIDDEN</visibility>

<visible>true</visible>

<visibility>DISPLAYED</visibility>

Tip

Refer to this GateIn Objects Schema file to see the possible "visibility" element values

The pages.xml contains the definition of the structure of each page.

In AIO, the instance-id is a string identifier for the window, indicating what portlet to instantiate. In Platform, this has been simplified largely, only the application and the portlet names are needed:

AIO Platform

<application>
  <instance-id>owner-type#owner-id:/application/portlet/window-id</instance-id>
</application>

<portlet-application>
  <portlet>
    <application-ref>application</application-ref>
    <portlet-ref>portlet</portlet-ref>
    <preferences><!-- ... --></preferences>
  </portlet>
  <!-- ... -->
</portlet-application>

The portlet-preferences.xml is used to configure portlet instances preferences. This is not be necessary in Platform, because the portlet preferences are now inlined in the pages.xml.

To migrate your portlet-preferences.xml, extract the <portlet-preferences> blocks and insert them in the corresponding <portlet-application> of the pages.xml.

AIO (portlet-preferences.xml) Platform (pages.xml)

<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-application>
  <portlet>
    <application-ref>web</application-ref>
    <portlet-ref>NavigationPortlet</portlet-ref>
    <preferences>
      <preference>
        <name>useAJAX</name>
        <value>true</value>
        <read-only>false</read-only>
      </preference>
    </preferences>
  </portlet>
  <!-- ... -->
</portlet-application>

In Platform, the edition of group and portal navigations is implemented by portlets. Hence, if you want to enable that feature in your portal, you will need to add these pages in the pages.xml and link them to navigation nodes in the navigation.xml. Read more about it in GateIn Reference Guide.

Group navigations are managed by the GroupNavigationPortlet :

<page>
  <name>groupnavigation</name>
  <title>Group Navigation</title>
  <access-permissions>*:/platform/users</access-permissions>
  <edit-permission>*:/platform/administrators</edit-permission>
  <portlet-application>
    <portlet>
      <application-ref>exoadmin</application-ref>
      <portlet-ref>GroupNavigationPortlet</portlet-ref>
    </portlet>
    <title>Group Navigation</title>
    <access-permissions>Everyone</access-permissions>
    <show-info-bar>false</show-info-bar>
    <show-application-state>false</show-application-state>
    <show-application-mode>false</show-application-mode>
  </portlet-application>
</page>

Portal navigations are managed by the PortalNavgationPortlet:

<page>
  <name>portalnavigation</name>
  <title>Portal Navigation</title>
  <access-permissions>*:/platform/users</access-permissions>
  <edit-permission>*:/platform/administrators</edit-permission>
  <portlet-application>
    <portlet>
      <application-ref>exoadmin</application-ref>
      <portlet-ref>PortalNavigationPortlet</portlet-ref>
    </portlet>
    <title>Portal Navigation</title>
    <access-permissions>Everyone</access-permissions>
    <show-info-bar>false</show-info-bar>
    <show-application-state>false</show-application-state>
    <show-application-mode>false</show-application-mode>
  </portlet-application>
</page>

Warning

Since you may not want to have them in your portal, these pages are not automatically added by the Migration Tool, it should be added manually !

You may have defined some custom Resource Bundles, it is no longer used/defined in a component configuration, you 've to change it into an external component plugin. In this external component plugin you will have to define only your own Resource Bundles, which means, Resource Bundles declaration should not be declared in your configuration:

AIO Platform

<component>
<key>org.exoplatform.services.resources.ResourceBundleService</key>
<type>org.exoplatform.services.resources.jcr.ResourceBundleServiceImpl</type>
<init-params>
...
</init-params>
</component>

<external-component-plugins>
 <!-- New Resource Bundles declaration (plugin the list of Resource Bundles) -->
 <target-component>org.exoplatform.services.resources.ResourceBundleService</target-component>
 <component-plugin>
	<!-- The name of the plugin -->
	<name>Sample ResourceBundle Plugin</name>
	<!-- The name of the method to call on the ResourceBundleService in order to register the ResourceBundles -->
	<set-method>addResourceBundle</set-method>
	<!-- The full qualified name of the BaseResourceBundlePlugin -->
	<type>org.exoplatform.services.resources.impl.BaseResourceBundlePlugin</type>
	<init-params>
	<!-- Keep only your own Resource Bundles declarations -->
...
	</init-params>
 </component-plugin>
</external-component-plugins>

If you have made some modifications in Resource Bundles in your AIO Server, you could extract all the Resource Bundles stored in the JCR by using the Migration Tools (see the Migration Tools Guide, section Resource Bundles Migration).

The Application Registry application can be configured to predefine categories and permissions on portlets and gadgets. If you have customized this configuration, you need to migrate.

AIO Platform

<component>
  <key>org.exoplatform.application.registry.ApplicationRegistryService</key>
<!-- AIO "ApplicationRegistryService" implementation -->
  <type>org.exoplatform.application.registry.impl.ApplicationRegistryServiceImpl</type>
...
<field name="applicationType">
	<string>portlet</string>
</field>
...
<field name="applicationGroup">
	<string>exoadmin</string>
</field>
...
</component>

<component>
  <key>org.exoplatform.application.registry.ApplicationRegistryService</key>
<!-- Platform "ApplicationRegistryService" implementation -->
  <type>org.exoplatform.application.registry.jcr.ApplicationRegistryServiceImpl</type>
...
<!-- "applicationType" is replaced by "type"-->
<field name="type">
	<string>portlet</string>
</field>
...
<!-- "applicationGroup" is replaced by "contentId"-->
<field name="contentId">
	<string>exoadmin</string>
</field>
...
</component>

You may have modified the applications and gadgets categories, by using the "Application Registry Portlet", this configuration is stored in the JCR. In order to extract this new configuration, you could use the Migration Tools ( see Migration Tools Guide, section Application Registry Migration).

If your code uses eXo APIs, you may be affected by some API changes.

In your gtmpl files, replace Groovy markers :

AIO Platform
$someVariable <%=someVariable%>

If you have implemented your own portlets, you will need to edit their web.xml :

  <servlet>
    <servlet-name>GateInServlet</servlet-name>
    <servlet-class>org.gatein.wci.api.GateInServlet</servlet-class>
    <load-on-startup>0</load-on-startup>
  </servlet>
  <servlet>
    <servlet-name>RestServer</servlet-name>
    <description>eXo - Platform REST Server</description>
    <servlet-class>org.exoplatform.services.rest.servlet.RestServlet</servlet-class>
    <load-on-startup>4</load-on-startup>
  </servlet>

The descriptor file of struts portlet (WEB-INF/portlet.xml) needs to be updated :

AIO Platform

<portlet>
  ...
  <init-param>
    <name>ServletContextProvider</name>
    <value>org.exoplatform.ServletContextProviderImpl</value>
  </init-param>
  ...
</portlet> 

<portlet>
   ...
   <init-param>
     <name>ServletContextProvider</name>
     <value>org.gatein.pc.bridge.GateInServletContextProvider</value>
   </init-param>
   ...
 </portlet> 

If you have made some live changes on ECM Administration templates and configurations, you will need to use the Migration Tools in order to extract the whole configurations in a Kernel's source format. See the Migration Tools Guide for more informations, sections:

If you have defined an ECM action, or Taxonomy Action, you have to change the type and the value of the field lifecyclePhase as follows:

AIO Platform

  <external-component-plugins>
    <target-component>org.exoplatform.services.cms.actions.ActionServiceContainer</target-component>
...
		<object type="org.exoplatform.services.cms.actions.impl.ActionConfig$Action">
...
		<!--AIO "lifecyclePhase" field declaration-->
		   <field name="lifecyclePhase">
			 <string>add</string>
		   </field>
...
		</object>
...
</external-component-plugins>

<external-component-plugins>
    <target-component>org.exoplatform.services.cms.actions.ActionServiceContainer</target-component>
...
		<object type="org.exoplatform.services.cms.actions.impl.ActionConfig$Action">
...
		<!--Platform "lifecyclePhase" field declaration-->
		  <field name="lifecyclePhase">
			<collection type="java.util.ArrayList">
			 <value><string>node_added</string></value>
			</collection>
		  </field>
...
		</object>
...
</external-component-plugins>

And the same thing for TaxonomyPlugin declaration:

AIO Platform

<external-component-plugins>
  <target-component>org.exoplatform.services.cms.taxonomy.TaxonomyService</target-component>
...
        <object type="org.exoplatform.services.cms.actions.impl.ActionConfig$TaxonomyAction">
...
         <!--AIO "lifecyclePhase" field declaration-->
         <field name="lifecyclePhase">
           <string>add</string>
         </field>
...
		</object>
...
</external-component-plugins>

<external-component-plugins>
  <target-component>org.exoplatform.services.cms.taxonomy.TaxonomyService</target-component>
...
  <object type="org.exoplatform.services.cms.actions.impl.ActionConfig$TaxonomyAction">
...
	 <!--Platform "lifecyclePhase" field declaration-->
	 <field name="lifecyclePhase">
	  <collection type="java.util.ArrayList">
	   <value>
		<string>node_added</string>
	   </value>
	  </collection>
	 </field>
...
	</object>
...
</external-component-plugins>

org.exoplatform.services.cms.actions.impl.ActionConfig can now accept a set of mixins. An interesting one is mix:affectedNodetype. It allows filtering the nodetype on which the action is triggered.

allowCreateFolders field declaration has been modified in the ECMS Drives declaration configuration:

AIO Platform

   <external-component-plugins>
      <target-component>org.exoplatform.services.cms.drives.ManageDriveService</target-component>
      <component-plugin>
...
		<type>org.exoplatform.services.cms.drives.impl.ManageDrivePlugin</type>
...
			<!-- AIO "allowCreateFolders" field declaration -->
                <field name="allowCreateFolder"><string>Both</string></field>
...
      </component-plugin>
</external-component-plugins>

   <external-component-plugins>
      <target-component>org.exoplatform.services.cms.drives.ManageDriveService</target-component>
...
		<type>org.exoplatform.services.cms.drives.impl.ManageDrivePlugin</type>
...
            <!-- Platform "allowCreateFolders" field declaration -->
            <field name="allowCreateFolders">
              <string>nt:folder,nt:unstructured</string>
            </field>
...
   </external-component-plugins>

AIO Platform

[...]
<type>org.exoplatform.services.cms.drives.impl.NewGroupListener</type>
[...]
<value-param>
 <name>allowCreateFolder</name>
 <value>Both</value>
</value-param>
[...]

[...]
<type>org.exoplatform.services.cms.drives.impl.NewGroupListener</type>
[...]
<value-param>
  <name>allowCreateFolder</name>
  <value>nt:folder,nt:unstructured</value>
</value-param>
<value-param>
  <name>allowNodeTypesOnTree</name>
  <value>*</value>
</value-param>
[...]

In Platform, the default publication public has changed to a new one, more flexible called Authoring plugin. The old StageAndVersion is now deprecated. It is recommended that you should upgrade to the new plugin. Read more about the new Authoring extension in ECMS reference guide.

To migrate gracefully, it is possible to define a lifecycle that behaves identically to the StageAndVersion plugin. Use the Migration Tools (see Migration Tools Guide, section WCM Contents Publication Migration).

Replace folksonomy service :

AIO Platform
import org.exoplatform.services.cms.folksonomy.FolksonomyService org.exoplatform.services.cms.folksonomy.NewFolksonomyService

For ECM groovy templates, follow this :

AIO Platform
uicomponent.isShowHeader() uicomponent.isShowField(UIPCLVPortlet.SHOWHEADER)

or uicomponent.isShowField(UICLVPortlet.PREFERENCESHOWHEADER) |

uicomponent.showRefreshButton(_) uicomponent.isShowField(UIPCLVPortlet.SHOWREFRESHBUTTON)

or isShowField(UICLVPortlet.PREFERENCESHOWREFRESHBUTTON) |

uicomponent.getPortletPreferences() portletRequest.getPreferences()  
UICLVPortlet.SHOWXX_ UICLVPortlet.PREFERENCESHOWXX_  
UICLVPortlet.SHOWTHUMBNAILSVIEW UICLVPortlet.PREFERENCESHOWILLUSTRATION  
def viewNode = Utils.getNodeView(node);

def contentNodeLocation = NodeLocation.getNodeLocationByNode(node);
def viewNode = Utils.getViewableNodeByComposer(contentNodeLocation.getRepository(), contentNodeLocation.getWorkspace(), contentNodeLocation.getPath());

 

In Platform, CSS and JavaScript integration adopts a new descriptor. Please refer to the skinning paragraph of the Developer guide. You can also read the Skinning & Javascript Configuration Chapters in the Reference guide of GateIn.

Web resources WARs (images, CSS and JavaScript) had some specific listeners declared in its web.xml files, this should be modified as the following table:

AIO Platform

<filter>
	<filter-name>ResourceRequestFilter</filter-name>
	<filter-class>org.exoplatform.portal.application.ResourceRequestFilter</filter-class>
</filter>
<filter-mapping>
	<filter-name>ResourceRequestFilter</filter-name>
	<url-pattern>/*</url-pattern>
</filter-mapping>
 <!-- Platform don't use this part anymore -->
 <listener>
   <listener-class>org.exoplatform.portal.webui.skin.SkinConfigListener</listener-class>
 </listener>
 <listener>
   <listener-class>org.exoplatform.portal.webui.javascript.JavascriptListener</listener-class>
 </listener>

<filter>
	<filter-name>ResourceRequestFilter</filter-name>
	<filter-class>org.exoplatform.portal.application.ResourceRequestFilter</filter-class>
</filter>
<filter-mapping>
	<filter-name>ResourceRequestFilter</filter-name>
	<url-pattern>/*</url-pattern>
</filter-mapping>

Note

Lean more about ResourceRequestFilter (section "3.1.5.2. Resource Request Filter").

In AIO, you load a JavaScript file thank to a descriptor called conf/script/groovy/JavascriptScript.groovy, it can be directly mapped to a <javascript> block in gatein-resources.xml.

AIO Platform

JavascriptService.addJavascript("module.name", "/path/to/file.js", ServletContext);

<javascript>
 <param>
	<js-module>module.name</js-module>
	<js-path>/path/to/file.js</js-path>
 </param>
</javascript>

In AIO, you declare a CSS thank to a descriptor called conf/script/groovy/SkinConfigScript.groovy. The content of this file is mapped to different blocks in gatein-resources.xml.

AIO Platform
 

SkinService.addPortalSkin("skinModule","skinName", "/path/to/file.css", ServletContext);

<portal-skin>
  <skin-name>skinName</skin-name>
  <skin-module>skinModule</skin-module>
  <css-path>/path/to/file.css</css-path>
</portal-skin>

 

SkinService.addSkin(
    "applicationName/portletName",
    "skinName",
    "/path/to/file.css",
    ServletContext
);

<portlet-skin>
  <application-name>applicationName</application-name>
  <portlet-name>portletName</portlet-name>
  <skin-name>skinName</skin-name>
  <css-path>/path/to/file.css</css-path>
</portlet-skin>

 

SkinService.addTheme("styleName", ["Theme1","Theme2"]);

<window-style>
 <style-name>styleName</style-name>
  <style-theme>
   <theme-name>Theme1</theme-name>
  </style-theme>
  <style-theme>
   <theme-name>Theme2</theme-name>
  </style-theme>
</window-style>

Once their content is migrated, you can delete your JavascriptScript.groovy and SkinConfigScript.groovy files.