You can develop many things both for and in Liferay: portlet OSGi modules (including ServiceBuilder OSGi modules), fragments, themes, layout templates, and more.
Gradle Workspace
Liferay DXP has introduced new toolings on the development environment, but Ant- or Maven-based plugin development environments are still supported. To get the full benefit of the OSGi module build environment, the following items need to be installed and configured according to the documentation. Many options of Blade or Gradle tasks are available, but the core behavior is same. Portlet OSGi modules have clean build and deploy tasks. Service Builder OSGi modules have clean buildService and deploy tasks.
Creating and Deploying New “Hello World” OSGi Module
Once all tools (Gradle and Blade CLI) are ready, a new project can be created and deployed using this Blade command:
$ cd modules; blade create -t mvc-portlet -p com.example.helloworld -c HelloWorld hello-world
$ cd hello-world; blade deploy
//Or
$ gradle deploy // if Gradle is installed in global path of your development environment
Anatomy of a Portlet Project
Anatomy of OSGi Module Portlet
The following directories and files are created when an OSGi module portlet is created by Blade CLI.
Folder |
Description |
src |
This folder is the “root” of your application. |
src/main/java |
Java packages including the controller class, action classes, resource action classes, etc. |
src/main/resources |
Module resources. |
src/main/resources/content |
Module-specific Language.properties. |
src/main/resources/META-INF/resources |
UI components such as JSP or JavaScript files. |
bnd.bnd |
Descriptor file to create an OSGi module. This file is the foundation of MANIFEST.MF, which controls the behavior of the OSGi module (dependency export/import) within the OSGi container. |
build.gradle |
Gradle build definition file that includes modules build dependencies, gradle tasks etc. |
Liferay Fragments
Fragments OSGi Module
Fragments are similar to hooks, but use OSGi technology. They’re designed for overriding Liferay’s JSP files.
Folder |
Description |
src |
This folder is the “root” of your application. |
src/main/resources |
Module resources. |
src/main/resources/META-INF/resources |
UI components such as JSP files to override using the same path defined in the target OSGi module to override. |
bnd.bnd |
Descriptor file to create an OSGi module. This file is the foundation of MANIFEST.MF, which controls the behavior of the OSGi module (dependency export/import) within the OSGi container. Fragment-Host needs to be defined in this file with a correct target module bundle-version. The fragment won’t be effective if bundle-version doesn’t match.
Fragment-Host: com.liferay.journal.web;bundle-version="1.4.0" |
build.gradle |
Gradle build definition file that includes module build dependencies, Gradle tasks, etc. |
JSP File Override
This allows overriding of any JSP from the core of Liferay by using the same paths Liferay uses within the specified directory. Use with care:
<hook>
<custom-jsp-dir>/META-INF/custom_jsp</custom-jsp-dir>
</hook>
Then, create custom JSPs:
/META-INF/custom_jsps/html/portlet/blogs/view.jsp
/META-INF/custom_jsps/html/portlet/calendar/week.jsp
Services
By wrapping services, it’s possible to extend any core Liferay service method to perform additional operations or replace the default operations.
<hook>
<service>
<service-type>
com.liferay.portal.service.UserLocalService
</service-type>
<service-impl>
com.liferay.test.hook.service.impl.MyUserLocalServiceImpl
</service-impl>
</service>
</hook>
Liferay Themes
Themes are plugins and are therefore hot-deployable, just like portlet plugins. You can use plugins to build your themes automatically so that they can be deployed to any Liferay instance. The Plugins SDK packages a theme into a .war file just like a portlet, and this .war file can then be hot-deployed to Liferay. However, Liferay DXP has introduced a set of new toolings to build themes and layout templates modules. To generate themes and successfully deploy them using the new toolings, this documentation will have to be followed. Also, install Node.js, Gulp, and Liferay Theme Generator.
Anatomy of a Theme
PathWithin Theme |
Description |
gulpfile.js |
Gulp JavaScript library for Gulp build tasks. |
liferay-theme.json |
Liferay theme deployment properties for app server path, deployment path, etc. |
package.json |
Liferay theme build properties defining theme name, dependencies, version, etc. |
node_modules |
Modules from Node.js for theme-building. |
src/css |
Folder to host CSS classes for the theme. |
src/fonts |
Folder to host fonts libraries for the theme. |
src/images |
Folder to host images for the theme. |
src/js |
Folder to host JavaScript for the theme. |
src/templates |
Folder to host FreeMarker template files for the theme. |
src/WEB-INF |
Folder to host
liferay-layout-templates.xml (if layout template is included in the theme)
liferay-look-and-feel.xml
liferay-plugin-package.properties |
Service Builder
Service Builder is a source code generation tool built by Liferay to automate the creation of interfaces and classes for database persistence and local and remote services. This is useful when developing data-driven applications that make frequent calls to the underlying database.
A “service” in Liferay is simply a class or set of classes designed to handle retrieving and storing data classes. A local service is used by code running in the local instance of Liferay, while a remote service can be accessed from anywhere over the internet or your local network. Remote services support SOAP, JSON, and Java RMI.
Sample Service
Services are defined by creating a service.xml file. Once defined, source code can be generated for the persistence and data access/transfer layers of your data-driven app. An example:
<service-builder package-path="com.sample.portlet.library">
<namespace>Library</namespace>
<entity name="Book" local-service="true" remote-service="true">
<!-- PK fields -->
<column name="bookId" type="long" primary="true" />
<!-- Group instance -->
<column name="groupId" type="long" />
<!-- Audit fields -->
<column name="companyId" type="long" />
<column name="userId" type="long" />
<column name="userName" type="String" />
<column name="createDate" type="Date" />
<column name="modifiedDate" type="Date" />
<!-- Other fields -->
<column name="title" type="String" />
</entity>
</service-builder>
New in OSGi Service Builder Module
The same API and Service package concept is applied in OSGi Service Builder module but they are generated as separate .jar files, service-builder-name-api.jar and service-builder-name-service.jar, where the API .jar module contains all interfaces and static utility classes that can be accessed by other modules if needed and the service .jar module contains all the implementations exposed via the API .jar module.
Artifact Name |
Description |
sample-common-service-api |
An OSGi module with interfaces and/or static utility classes. Other modules in the same OSGi container communicate through the API module.
The bnd.bnd file from this module exposes any services that need to be consumed by other modules in the same OSGi container. |
sample-common-service-service |
An OSGi module with implementations of all services built from service.xml. |
Generating the Code
$ gradle buildService
Or
$ blade buildService
Liferay’s portal, content, and collaboration frameworks are tied together using a rich suite of social features. For developers, plugging social software into Liferay can be achieved in many ways; for example, using the native Social Relationship API for managing relationships between users (via the com.liferay.portlet. social package), interacting with the Activity Stream (via the SocialActivity model), calculating and visualizing Social Equity participation and contribution values, or dropping OpenSocial gadgets onto a page and managing them via Liferay’s Control Panel.
Service Access Policy
RESTful APIs that we can expose via Service Builder can have individualized service access policies. Each API call can be specifically exposed via Service Access Policy.
{{ parent.title || parent.header.title}}
{{ parent.tldr }}
{{ parent.linkDescription }}
{{ parent.urlSource.name }}