Follow these steps to create an upgrade process for your module:
-
Open your module’s
bnd.bnd
file, and specify aLiferay-Require-SchemaVersion
header with the new schema version value. Here’s an example schema version header for a module whose new schema is version1.1
:Liferay-Require-SchemaVersion: 1.1
-
Add a dependency on the
com.liferay.portal.upgrade
module, along with any other modules your upgrade process requires, in your your module’s dependency management file (e.g., Maven POM, Gradle build file, or Ivyivy.xml
file). An example configuration for abuild.gradle
file is shown below:compile group: "com.liferay", name: "com.liferay.portal.upgrade.api", version: "2.0.3"
-
Create an
UpgradeProcess
class that extends theUpgradeProcess
base class ( which implements theUpgradeStep
interface):public class MyUpgradeSchemaClass extends UpgradeProcess { ... }
-
Override the
UpgradeProcess
class’sdoUpgrade()
method with instructions for modifying the database. Use therunSQL
andrunSQLTemplate*
methods (inherited from theBaseDBProcess
class) to execute your SQL commands and SQL DDL, respectively. If you want to create, modify, or drop tables or indexes by executing DDL sentences from an SQL file, make sure to use ANSI SQL only. Doing this assures the commands work on different databases. If you need to use non-ANSI SQL, it’s best to write it in theUpgradeProcess
class’srunSQL
oralter
methods, along with tokens that allow porting the sentences to different databases, as shown in journal-service module’sUpgradeSchema
upgrade step class below which uses therunSQLTemplateString
method to execute ANSI SQL DDL from an SQL file and thealter
method andUpgradeProcess
’sUpgradeProcess.AlterColumnName
andUpgradeProcess.AlterColumnType
inner classes as token classes to modify column names and column types:public class UpgradeSchema extends UpgradeProcess { @Override protected void doUpgrade() throws Exception { String template = StringUtil.read( UpgradeSchema.class.getResourceAsStream("dependencies/update.sql")); runSQLTemplateString(template, false, false); upgrade(UpgradeMVCCVersion.class); alter( JournalArticleTable.class, new AlterColumnName( "structureId", "DDMStructureKey VARCHAR(75) null"), new AlterColumnName( "templateId", "DDMTemplateKey VARCHAR(75) null"), new AlterColumnType("description", "TEXT null")); alter( JournalFeedTable.class, new AlterColumnName("structureId", "DDMStructureKey TEXT null"), new AlterColumnName("templateId", "DDMTemplateKey TEXT null"), new AlterColumnName( "rendererTemplateId", "DDMRendererTemplateKey TEXT null"), new AlterColumnType("targetPortletId", "VARCHAR(200) null")); } }
Here’s a simpler example upgrade step from the
com.liferay.calendar.service
module. It uses thealter
method to modify a column type in the calendar booking table:public class UpgradeCalendarBooking extends UpgradeProcess { @Override protected void doUpgrade() throws Exception { alter( CalendarBookingTable.class, new AlterColumnType("description", "TEXT null")); } }
-
If your application was modularized from a former traditional Liferay plugin application (application WAR) and it uses Service Builder, create and register a Bundle Activator to register it in Liferay DXP’s
Release_
table. -
Create an
UpgradeStepRegistrator
OSGi Component class of service typeUpgradeStepRegistrator.class
that implements theUpgradeStepRegistrator
interface:package com.liferay.mycustommodule.upgrade; import com.liferay.portal.upgrade.registry.UpgradeStepRegistrator; import org.osgi.service.component.annotations.Component; @Component(immediate = true, service = UpgradeStepRegistrator.class) public class MyCustomModuleUpgrade implements UpgradeStepRegistrator { }
-
Override the
register
method to implement the module’s upgrade registrations—abstractions for the upgrade steps required to update the database from one schema version to the next. For example, the upgrade step registrator classMyCustomModuleUpgrade
(below) registers three upgrade steps incrementally for each schema version (past and present,0.0.0
to2.0.0
,1.0.0
to1.1.0
, and1.1.0
to2.0.0
).The first registration is applied if the module hasn’t been installed previously. It contains only one empty upgrade step: new
DummyUpgradeStep
(). This registration records the module’s latest schema version (i.e.,2.0.0
) in Liferay DXP’sRelease_
table. Note that if the same class name is used in multiple packages, you must provide the fully qualified class name for the class, as shown in the second registration (1.0.0
to1.1.0
) below for theUpgradeFoo
class:package com.liferay.mycustommodule.upgrade; import com.liferay.portal.upgrade.registry.UpgradeStepRegistrator; import org.osgi.service.component.annotations.Component; @Component(immediate = true, service = UpgradeStepRegistrator.class) public class MyCustomModuleUpgrade implements UpgradeStepRegistrator { @Override public void register(Registry registry) { registry.register( "com.liferay.mycustommodule", "0.0.0", "2.0.0", new DummyUpgradeStep()); registry.register( "com.liferay.mycustommodule", "1.0.0", "1.1.0", new com.liferay.mycustommodule.upgrade.v1_1_0.UpgradeFoo()); registry.register( "com.liferay.mycustommodule", "1.1.0", "2.0.0", new com.liferay.mycustommodule.upgrade.v2_0_0.UpgradeFoo(), new UpgradeBar()); } }
-
If your upgrade step uses an OSGi service, your upgrade must wait for that service’s availability. Use the
@Reference
annotation to declare any classes that the registrator class depends on. For example, theWikiServiceUpgrade
registrator class below references theSettingsFactory
class for theUpgradePortletSettings
upgrade step. ThesetSettingsFactory
method’s@Reference
annotation declares that the registrator class depends on and must wait for theSettingsFactory
service to be available in the run time environment:@Component(immediate = true, service = UpgradeStepRegistrator.class) public class WikiServiceUpgrade implements UpgradeStepRegistrator { @Override public void register(Registry registry) { registry.register("0.0.1", "0.0.2", new UpgradeSchema()); registry.register("0.0.2", "0.0.3", new UpgradeKernelPackage()); registry.register( "0.0.3", "1.0.0", new UpgradeCompanyId(), new UpgradeLastPublishDate(), new UpgradePortletPreferences(), new UpgradePortletSettings(_settingsFactory), new UpgradeWikiPage(), new UpgradeWikiPageResource()); registry.register("1.0.0", "1.1.0", new UpgradeWikiNode()); registry.register( "1.1.0", "1.1.1", new UpgradeDiscussionSubscriptionClassName( _subscriptionLocalService, WikiPage.class.getName(), UpgradeDiscussionSubscriptionClassName.DeletionMode.ADD_NEW)); registry.register( "1.1.1", "2.0.0", new BaseUpgradeSQLServerDatetime( new Class<?>[] {WikiNodeTable.class, WikiPageTable.class})); } @Reference private SettingsFactory _settingsFactory; @Reference private SubscriptionLocalService _subscriptionLocalService; }
-
Upgrade the database to the latest database schema version before making its services available. To do this, configure the Bnd header
Liferay-Require-SchemaVersion
to the latest schema version for Service Builder services. For all other services, specify an@Reference
annotation that targets the containing module and its latest schema version.Here are the target’s required attributes:
release.bundle.symbolic.name
: module’s bundle symbolic namerelease.schema.version
: module’s current schema version
For example, the
com.liferay.comment.page.comments.web
module’sPageCommentsPortlet
class upgrades to schema version2.0.0
by defining the reference below:@Reference( target = "(&(release.bundle.symbolic.name=com.liferay.comment.page.comments.web)(release.schema.version=2.0.0))" ) private Release _release;
Dependencies between OSGi services can reduce the number of service classes in which upgrade reference annotations are needed. For example, there’s no need to add an upgrade reference in a dependent service, if the dependency already refers to the upgrade.
Great! Now you know how to create data upgrades for all your modules.