Sunday, 18 May 2025

Install Liferay DXP 7.4 With Postgres SQL + Install Liferay Developer Studio + Set Up Liferay Workspace

Install Liferay DXP 7.4 With PostgreSQL + Liferay Developer Studio

This tutorial walks you through installing Liferay DXP 7.4, connecting it with PostgreSQL, setting up Liferay Developer Studio, and initializing a modular workspace.


๐Ÿ”ง 1. Prerequisites

  • Java JDK 8 or 11
  • PostgreSQL 12 or later
  • Liferay DXP 7.4 bundle (.zip)
  • Liferay Developer Studio (Eclipse-based IDE)

๐Ÿ›  2. Install and Configure PostgreSQL

  1. Install PostgreSQL from official site.
  2. Create a database and user for Liferay:
CREATE DATABASE lportal;
CREATE USER liferayuser WITH PASSWORD 'liferay';
GRANT ALL PRIVILEGES ON DATABASE lportal TO liferayuser;

๐Ÿ“ฆ 3. Download and Extract Liferay DXP 7.4

  • Obtain the Liferay DXP 7.4 bundle from your customer portal.
  • Extract it to a preferred directory, e.g., C:\liferay\dxp-7.4

๐Ÿ”Œ 4. Configure Database Connection

Modify portal-ext.properties in liferay-dxp-7.4/tomcat-9.0.56/webapps/ROOT/WEB-INF/classes or create one in the root:

jdbc.default.driverClassName=org.postgresql.Driver
jdbc.default.url=jdbc:postgresql://localhost:5432/lportal
jdbc.default.username=liferayuser
jdbc.default.password=liferay

Place the PostgreSQL JDBC driver postgresql-.jar into:

liferay-dxp-7.4/tomcat-*/lib/ext

๐Ÿš€ 5. Start Liferay DXP

Start the server using:

cd liferay-dxp-7.4/tomcat-*/bin  
./startup.sh (Linux/macOS) OR startup.bat (Windows)

Wait for first-time setup and access:

http://localhost:8080

๐Ÿง‘‍๐Ÿ’ป 6. Install Liferay Developer Studio

  1. Download from: https://liferay.dev/studio
  2. Install and launch the IDE.

๐Ÿ—‚ 7. Set Up Liferay Workspace

  1. In Liferay Developer Studio, go to File → New → Liferay Workspace Project
  2. Set the name (e.g., my-liferay-workspace)
  3. Use the default Gradle build type
  4. Link to Liferay DXP bundle (in liferay.workspace.home)

๐Ÿ’ก 8. Create Your First Module

File → New → Liferay Module Project

Choose template (e.g., MVC Portlet), and define:

  • Project name: sample-portlet
  • Component class name: SamplePortlet

๐Ÿ“‚ Directory Structure Overview

my-liferay-workspace/
 ├── bundles/
 ├── modules/
 ├── themes/
 ├── wars/
 └── gradle.properties

๐Ÿšข 9. Deploy the Portlet

Deploy the portlet from Developer Studio or via terminal:

./gradlew deploy

Your portlet should now appear in the Liferay UI → Add → Widgets → Sample Portlet


✅ Conclusion

You have now set up Liferay DXP 7.4 with PostgreSQL, configured your development environment, and created your first module using Liferay Developer Studio and Workspace.

๐Ÿ“š References

Polls in liferay dxp

Polls in Liferay DXP

Liferay DXP provides a way to create and manage polls either using its classic built-in Polls portlet or by developing your own custom Poll feature using Service Builder. In this blog, we’ll explore both approaches.

✅ Option 1: Using Built-In Polls (If Available)

Liferay used to ship with a Polls portlet in older versions, which may still be available in some distributions via Marketplace. You can:

  • Deploy the Polls portlet from Liferay Marketplace.
  • Add the Polls widget to a site page.
  • Create a poll question, define choices, and track responses.

๐Ÿ›  Option 2: Custom Poll Portlet with Service Builder

If you want full control or Polls is not available, you can create your own:

Step 1: Create Modules

  • poll-api – Contains service interfaces and models
  • poll-service – Contains service implementations
  • poll-web – Contains portlet UI

Step 2: Define Entities in Service Builder XML

<entity name="Poll" local-service="true" remote-service="false">
    <column name="pollId" type="long" primary="true" />
    <column name="question" type="String" />
    <column name="createDate" type="Date" />
    <column name="modifiedDate" type="Date" />
</entity>

<entity name="PollOption" local-service="true" remote-service="false">
    <column name="optionId" type="long" primary="true" />
    <column name="pollId" type="long" />
    <column name="optionText" type="String" />
    <column name="votes" type="int" />
</entity>

Step 3: Run Service Builder

Run the command:

./gradlew buildService

Step 4: Add Service Methods

In `PollLocalServiceImpl`, add methods like:

public Poll addPoll(String question, ServiceContext serviceContext) {
    long pollId = counterLocalService.increment(Poll.class.getName());

    Poll poll = pollPersistence.create(pollId);
    poll.setQuestion(question);
    poll.setCreateDate(new Date());

    return pollPersistence.update(poll);
}

Step 5: Create the UI (poll-web module)

Use JSP or React to display:

  • The poll question
  • Options as radio buttons
  • Submit button to vote
  • Vote count after submission

Example Form Snippet

<form action="<portlet:actionURL name='submitVote' />" method="post">
    <label>What is your favorite programming language?</label><br/>
    <input type="radio" name="optionId" value="1" /> Java<br/>
    <input type="radio" name="optionId" value="2" /> Python<br/>
    <input type="radio" name="optionId" value="3" /> JavaScript<br/>
    <button type="submit">Vote</button>
</form>

๐Ÿ“Š Viewing Results

You can display a summary below the poll form with vote counts using a method in your service layer like:

public Map<String, Integer> getResults(long pollId) {
    List<PollOption> options = pollOptionPersistence.findByPollId(pollId);
    Map<String, Integer> results = new HashMap<>();
    for (PollOption option : options) {
        results.put(option.getOptionText(), option.getVotes());
    }
    return results;
}

๐Ÿ”’ Permissions

Use Liferay’s permission framework to restrict who can vote or view poll results.

๐Ÿ“ฆ Deploy and Test

Deploy the API, Service, and Web modules using Gradle. Add the portlet to a page and verify everything works as expected.

๐Ÿง  Conclusion

Polls in Liferay can be simple or complex depending on your needs. If built-in support is not present, creating a custom poll feature with Service Builder gives you full flexibility over functionality, UI, and data handling.

๐Ÿ“š References

Saturday, 17 May 2025

DSLQuery (or Dynamic Query) in Liferay DXP

DSLQuery (or Dynamic Query) in Liferay DXP

In Liferay DXP 7.3 and later, DSLQuery provides a modern, type-safe API to query your database. It replaces the older DynamicQuery mechanism and integrates deeply with Service Builder entities.

๐Ÿ›  Prerequisites

  • Liferay DXP 7.3 or higher
  • Service Builder module with generated entities
  • Familiarity with Java and Liferay’s modular structure

๐Ÿ”Ž What is DSLQuery?

DSLQuery (Domain Specific Language Query) is a fluent API built on top of SQL. It’s used to perform select, count, and aggregate operations on Service Builder entities.

๐Ÿ” Example: Fetch All Products Using DSLQuery

import com.example.sb.model.ProductTable;
import com.example.sb.model.Product;
import com.liferay.petra.sql.dsl.query.DSLQueryFactoryUtil;
import com.liferay.portal.kernel.dao.orm.QueryUtil;
import com.liferay.portal.kernel.service.persistence.impl.BasePersistenceImpl;

import java.util.List;

DSLQuery dslQuery = DSLQueryFactoryUtil.select(
    ProductTable.INSTANCE
).from(
    ProductTable.INSTANCE
);

List<Product> products = ProductLocalServiceUtil.dslQuery(dslQuery);
  

๐Ÿ” Filtering with WHERE Clause

DSLQuery dslQuery = DSLQueryFactoryUtil.select(
    ProductTable.INSTANCE
).from(
    ProductTable.INSTANCE
).where(
    ProductTable.INSTANCE.price.gt(100.0)
);
List<Product> expensiveProducts = ProductLocalServiceUtil.dslQuery(dslQuery);
  

๐Ÿ“Š Aggregate Count with DSLQuery

long count = ProductLocalServiceUtil.dslQueryCount(
    DSLQueryFactoryUtil.count(
        ProductTable.INSTANCE.productId
    ).from(ProductTable.INSTANCE)
);
  

๐Ÿ•ต️ DynamicQuery (Older Approach)

Still supported in Liferay 7.x, useful for backwards compatibility:

DynamicQuery dynamicQuery = DynamicQueryFactoryUtil.forClass(Product.class);
dynamicQuery.add(RestrictionsFactoryUtil.gt("price", 100.0));
List<Product> results = ProductLocalServiceUtil.dynamicQuery(dynamicQuery);
  

๐Ÿ“˜ When to Use DSLQuery vs DynamicQuery

  • Use DSLQuery – For new development, better performance, type safety
  • Use DynamicQuery – When maintaining older codebases, or where DSLQuery support is missing

⚠️ Notes

  • DSLQuery returns raw models (not wrapped with SOAP or JSON layers).
  • Make sure to import correct classes (especially ProductTable) from generated API module.
  • DSLQuery does not support all SQL features (e.g., joins between unrelated tables may be limited).

๐Ÿ“š Resources

✅ Conclusion

DSLQuery is Liferay’s preferred querying mechanism for efficient and type-safe data access in OSGi-based modular projects. You should prefer it over DynamicQuery for new development.

Using Service Builder in Modular Liferay Projects (OSGi Modules)

Using Service Builder in Modular Liferay Projects (OSGi Modules)

Service Builder is one of the most powerful tools provided by Liferay for generating database interaction layers. In modular OSGi-based Liferay projects, it allows you to define entities and auto-generate service layers that are ready for use across modules.

๐Ÿงฐ Prerequisites

  • Liferay 7.x or Liferay DXP workspace
  • Blade CLI installed
  • Basic understanding of OSGi modular structure

๐Ÿ“ฆ Step 1: Create Service Builder Module

blade create -t service-builder -p com.example.sb -c Product product-sb

This creates 3 modules:

  • product-sb-api – Interface layer
  • product-sb-service – Implementation layer
  • product-sb – Portlet or UI module (optional)

๐Ÿ“ Step 2: Define Entity in service.xml

Edit product-sb-service/src/main/resources/META-INF/service.xml

<?xml version="1.0"?>
<service-builder package-path="com.example.sb">

  <author>YourName</author>

  <namespace>SB</namespace>

  <entity name="Product" local-service="true" remote-service="false">
    <column name="productId" type="long" primary="true" />
    <column name="name" type="String" />
    <column name="price" type="double" />
  </entity>

</service-builder>

⚙️ Step 3: Build Services

./gradlew buildService

This will generate:

  • Persistence layer
  • Local service interfaces and implementations
  • ServiceUtil classes for easy access

๐Ÿ”Œ Step 4: Use the Generated Services

In any other OSGi module, include a dependency on the API module:

dependencies {
    compileOnly project(":modules:product-sb:product-sb-api")
}

Inject the local service using OSGi annotations:

@Reference
private ProductLocalService productLocalService;

Then you can use the service like this:

Product product = productLocalService.createProduct(counterLocalService.increment());
product.setName("Phone");
product.setPrice(499.99);
productLocalService.addProduct(product);

๐Ÿš€ Step 5: Deploy and Test

Deploy all the modules using:

./gradlew deploy

Use Gogo shell or custom portlet to test service calls.

๐Ÿงช Example Gogo Shell Test

:load com.example.sb.service.ProductLocalService
productLocalService.getProducts(0, 10)

๐Ÿ“˜ Summary

  • Service Builder works well in modular OSGi Liferay projects.
  • You can generate entities and services with a simple XML.
  • Split code into clean layers: API and SERVICE.
  • Can be consumed from any OSGi portlet or module.

๐Ÿ”— Useful Resources

Adding Custom Finder Methods in Liferay Service Builder

Adding Custom Finder Methods in Liferay Service Builder

Adding Custom Finder Methods in Liferay Service Builder

Liferay’s Service Builder is a powerful tool for creating database-backed services. In many real-world applications, you need to fetch data using custom criteria. This guide walks you through creating custom finder methods using Liferay's Service Builder with full detail.

๐Ÿงฐ Prerequisites

  • Liferay Workspace (7.x or DXP)
  • Blade CLI or IDE (e.g., IntelliJ or Eclipse)
  • Basic knowledge of Service Builder

๐Ÿ“ฆ Step 1: Create a Service Builder Module

blade create -t service-builder -p com.example.custom -c Example example-finder

This will create three modules:

  • example-finder-api
  • example-finder-service
  • example-finder

๐Ÿ“ Step 2: Define the Entity in service.xml

Edit example-finder-service/src/main/resources/META-INF/service.xml:

<entity name="Employee" local-service="true" remote-service="false" table="Employee">
  <column name="employeeId" type="long" primary="true" />
  <column name="name" type="String" />
  <column name="department" type="String" />
</entity>

After updating, run:

./gradlew buildService

๐Ÿ” Step 3: Create a Custom Finder Method

➡️ 3.1 Create Method in EmployeeFinder Interface

File: example-finder-api/src/main/java/com/example/custom/service/persistence/EmployeeFinder.java

package com.example.custom.service.persistence;

import java.util.List;
import com.example.custom.model.Employee;

public interface EmployeeFinder {
    List<Employee> findByDepartment(String department);
}

➡️ 3.2 Implement in EmployeeFinderImpl

File: example-finder-service/src/main/java/com/example/custom/service/persistence/impl/EmployeeFinderImpl.java

package com.example.custom.service.persistence.impl;

import com.example.custom.model.Employee;
import com.example.custom.service.persistence.EmployeeFinder;
import com.liferay.portal.kernel.dao.orm.*;
import com.liferay.portal.kernel.service.persistence.impl.BasePersistenceImpl;
import org.osgi.service.component.annotations.Component;

import java.util.List;

@Component(service = EmployeeFinder.class)
public class EmployeeFinderImpl extends BasePersistenceImpl<Employee> implements EmployeeFinder {

    public List<Employee> findByDepartment(String department) {
        Session session = null;

        try {
            session = openSession();

            String sql = "SELECT * FROM Employee WHERE department = ?";
            SQLQuery query = session.createSQLQuery(sql);
            query.setCacheable(false);
            query.addEntity("Employee", getModelClass());
            query.setString(0, department);

            return query.list();

        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("Failed to execute custom finder", e);
        } finally {
            closeSession(session);
        }
    }
}

๐Ÿ”— Step 4: Access Custom Finder from LocalServiceImpl

Use the finder in EmployeeLocalServiceImpl.java:

public List<Employee> getEmployeesByDepartment(String department) {
    return employeeFinder.findByDepartment(department);
}

๐Ÿ“Œ Step 5: Build and Deploy

./gradlew buildService
./gradlew deploy

๐Ÿงช Step 6: Test Your Custom Finder

Call your service method using:

  • REST endpoint (if exposed)
  • JSP/React portlet
  • Integration test

๐Ÿ“˜ Summary

  • We created a custom finder in Liferay using Service Builder
  • Used raw SQL and the BasePersistenceImpl class
  • Injected and called it in the service layer

๐Ÿ”— Useful Links

Creating Custom Portlets with Liferay DXP + Java.

Creating Custom Portlets with Liferay DXP + Java

Liferay DXP (Digital Experience Platform) provides a modular framework for developing robust web applications using Java. In this blog, we will walk through the steps required to create a custom portlet using Liferay DXP with Java, covering even the smallest configuration and setup details.

Prerequisites

  • JDK 11 or later
  • Liferay DXP 7.4 (or any compatible version)
  • Blade CLI installed
  • IDE like IntelliJ IDEA or Eclipse

Step 1: Set up Liferay Workspace

Open terminal and run the following command:

blade init liferay-workspace

Navigate to your workspace:

cd liferay-workspace

Step 2: Create a Portlet Module

blade create -t mvc-portlet -p com.example.portlet -c CustomPortlet custom-portlet

This command creates a new portlet module using the MVC Portlet template.

Step 3: Explore the Generated Files

  • CustomPortlet.java - The main class for the portlet.
  • view.jsp - Default view template for the portlet.
  • bnd.bnd - Contains OSGi metadata.

Step 4: Update view.jsp

Edit src/main/resources/META-INF/resources/view.jsp to customize the UI:

<%@ page contentType="text/html;charset=UTF-8" %>
<h1>Welcome to My Custom Portlet</h1>
<p>This is a custom portlet built with Java.</p>

Step 5: Build and Deploy the Portlet

./gradlew deploy

This will deploy your portlet to the Liferay DXP instance.

Step 6: Add the Portlet to a Page

  1. Login to the Liferay portal.
  2. Navigate to a site page or create a new one.
  3. Click on the "+" button to add a widget.
  4. Search for your portlet (e.g., "Custom Portlet").
  5. Drag and drop it onto the page.

Step 7: Customize Further (Optional)

You can create additional JSPs and actions, or use Spring MVC for more complex logic. You can also define PortletPreferences, add localization files, and implement inter-portlet communication using public render parameters.

Conclusion

You've now successfully created a custom portlet with Liferay DXP using Java. From setting up the workspace to deploying the module, each step builds your foundation for more advanced Liferay development.