Liferay 7.3.5 CE portlet development and Liferay commerce: Hit the ground running with a docker based setup

Abstract :

Setting up Liferay development environment by installing Liferay binaries and running them on the local laptop with a custom MySQL database involves installing the database, establishing connectivity and ensuring that the desktop setup has all environment settings configured to run continuously during development. A more easier approach is the serverless one, where we spin up docker containers and can be up and running quickly.

A similar approach applies for Liferay commerce too where one can spin up a Liferay commerce server using a docker image and build an ecommerce site using the minimum accelerator within no time.

Objective:

Our objective is to see how to:

  1. Setup Liferay 7.3.5 connected to MySQL 5.7 in a docker container
  2. Setup Liferay commerce 2.0.5 to a docker container and spin up our own ecommerce site
  3. Write a Jython portlet and run it in Liferay

Setup Liferay 7.3.5 connected to MySQL 5.7 in a docker container

  1. Clone the code available in the GitHub repo : https://github.com/ragnaray/liferay-mysql-custom/tree/master/liferay-portal
  2. download liferay-ce-portal-tomcat-7.3.5-ga6-20200930172312275.tar and copy to liferay-portal\configs\common
  3. Open in Intellij editor
  4. Install the Liferay Intellij Plugin from marketplace
  5. Create a Liferay workspace in Intellij File → New → Project
  6. Select the Liferay option on the left menu bar and choose Liferay Maven workspace and click Next
  1. Select the name of your project (for eg. liferay-portal)
  1. Choose the folder in which you will create your workspace and click Finish.
  2. Run the following commands to build the custom MySQL DB docker image and push it to your own docker repo (lets call it https://hub.docker.com/repository/docker/goldvault)
  • docker build -t mysql_liferay:latest .
  • docker tag mysql_liferay:latest goldvault/mysql_liferay:latest
  • docker push goldvault/mysql_liferay:latest

10. Run the following commands to build the liferay portal docker image and push it to your own docker repo

  • docker build -t liferay:latest .
  • docker tag liferay:latest goldvault/liferay:latest
  • docker push goldvault/liferay:latest

11. Create a new docker-compose.yml with the following instructions

version: '3.4'
services:
  liferay:
    image: "goldvault/liferay:latest"
    depends_on:
      - mysql_liferay
    volumes:
      - "./configs/docker/osgi/modules:/opt/liferay/deploy"
      - "./configs/dev/portal-ext.properties:/opt/liferay/portal-ext.properties"
    ports:
      - "8080:8080"
      - "9000:9000"
      - "8000:8000"
      - "11311:11311"
    environment:
      - "LIFERAY_HOME=/opt/liferay"
      - "CATALINA_HOME=/opt/tomcat"
      - "JAVA_OPTS=-Xdebug -Xrunjdwp:server=y,transport=dt_socket,address=8000,suspend=n"
    networks:
      - lfrnet
  mysql_liferay:
    container_name: "mysql_dev"
    image: "goldvault/mysql_liferay:latest"
    ports:
      - "3306:3306"
    environment:
      - "MYSQL_ROOT_PASSWORD=root"
    networks:
      - lfrnet

networks:
  lfrnet:

12.run the command

docker-compose up 

from the folder containing this docker-compose.yml file

13.You will get some errors initially, then run docker-compose stop

14.Next run docker-compose start

15.Navigate to localhost:8080 and enter your email , accept terms and conditions.

You are now all set to start your portlet development

Setup Liferay commerce 2.0.5 to a docker container and spin up our own ecommerce site

  1. Run
docker pull liferay/commerce:2.0.5
docker run -it -p 8080:8080 liferay/commerce:2.0.5
Docker desktop images

2. Open a new browser and navigate to : https://localhost:8080

3. Click the Sign In link and enter the default liferay credentials test@liferay.com/test

4. Next open the Product Menu  and navigate to the Account Menu -> My Account -> Account Settings. In the information tab add a new user information for admin user admin@liferay.com and password <mysecretgoldvault#007>

5. Sign-out of your account.

6. Next we shall be using the Liferay out-of-box Minimum accelerator to build our quick ecommerce site.  Navigate to Control Panel → Sites → Sites, Click the Add (+) button to add a new site, Choose an Accelerator (Minimum).

7. Enter a name: minime.iot.store, Click Save, In the Site Menu click Go to Site.

8. Here we shall be using all the default pages and widgets provided by Minimum. Customization of the pages is out of scope of this blog. (The store is currently facing problems hiring developers due to their very high expected salary)

9. Presented below are all the out-of-box pages that will be customized as part of our project Vulcan when Dr Evil is able to hire Austin the developer, Vanessa the Business Analyst and Frau the Project Manager from the market.

Main site listing page
Search Catalog page
Order details page
Orders placed page
Enable payment gateway page

Write a Jython portlet and run it in Liferay

While we all agree that java is de-facto language for developing portlets. Jython has several advantages:

  1. Python syntax (used by Jython) is considerably more concise and quicker to develop for many programmers.
  2. Use can use the several data analytics libraries readily available in python and enjoy the benefits of both the UI based portlet world and the processing power of python.

So lets get going

  1. Install Jython on ubuntu using the command apt install Jython
  2. jip is a package manager similar to pip which we shall be using to install java libraries in python. Navigate to : https://pypi.org/project/jip/#files and download jip-0.9.15.tar.gz (22.6 kB)
  3. untar the file and navigate to the folder containing setup.py. run
jython setup.py install 

4. You can now go ahead and install all required java libraries using the command

jip install <groupId>:<artifactId>:<version>
eg. 
jip install javax.portlet:portlet-api:3.0.0
jip install org.apache.portals.bridges:portals-bridges-script-dependencies-jython:2.0
jip list
jip remove xerces:xercesImpl:2.9.1

5. Create a HelloJython.py file to host our portlet code

from jip.embed import require

require('javax.portlet:portlet-api:3.0.0')

from javax.portlet import GenericPortlet

#require('xerces:xerces:2.4.0')

#from org.apache.xerces.parsers import SAXParser

	
#
# HelloJython.py
#
class HelloJython(GenericPortlet):
    def doView(self, request, response):
        greeting = "<H1>Hello, Jython!</H1>"
        response.writer.println(greeting)
        
    

# Return portlet instance as a last evaluated object
# because ScriptPortlet expects the evaluated result object 
# as a portlet class or non-initialized portlet instance.
value = HelloJython()

6. Create a portlet.xml file similar to the one below

<?xml version="1.0" encoding="UTF-8"?>
<portlet-app id="velocitysimplest" version="1.0">
  
  <portlet>
    <portlet-name>HelloJython</portlet-name>
    <display-name>Hello Jython</display-name>
    <portlet-class>org.apache.portals.bridges.script.ScriptPortlet</portlet-class>
   
    <!-- Optional init parameter for script engine 
    If this init parameter is not set, the ScriptPortlet will look up a script engine automatically
    by the mimeType or the extension of the script source file. -->
    <init-param>
      <name>engine</name>
      <!-- 
        Note: You can set other script engine which support JSR-223 ScriptEngine
        such as 'groovy', 'jruby', 'jython'.
      --> 
      <value>jython</value>
    </init-param>
   
    <!-- Optional init parameter for the key for portlet/preferencesValidator class or 
    portlet/preferencesValidator instance which is evaluated and returned by the script.
    By default, when this init parameter is not set, ScriptPortlet retrieves 
    the last evaluated object from the script.
    If you set this to 'value', then ScriptPortlet retrieves an object named 'value' 
    from the bindings of the script engine.
    Depending on script engines, this init parameter should be properly configured 
    because some script engines do not return the last evaluated object. -->
    <init-param>
      <name>eval-key</name>
      <value>value</value>
    </init-param>
   
    <!-- Required init parameter for script source path -->
    <init-param>
      <name>source</name>
      <!--
        Note: You can set script source in three ways. 
        The first is to use context relative path,
        the second is to use file: url, 
        and the third is to classpath: uri.
        Here are the examples for each way.
      -->
      <!--
        <value>/WEB-INF/groovy/HelloGroovy.groovy</value>
        <value>file:/C:/Program Files/Tomcat/webapps/demo/WEB-INF/groovy/HelloGroovy.groovy</value>
        <value>classpath:org/apache/portals/bridges/script/HelloGroovy.groovy</value>
      -->
      <value>classpath:org/apache/portals/bridges/script/HelloJython.py</value>
    </init-param>
   
    <!-- Optional init parameter for script file content encoding. The default value is 'UTF-8'. -->
    <init-param>
      <name>encoding</name>
      <value>UTF-8</value>
    </init-param>
   
    <!-- Optional init parameter for auto-refresh option.
    If auto-refresh is true, then a modification of script source can be refreshed automatically.
    By default, this option is set to false. -->
    <init-param>
      <name>auto-refresh</name>
      <value>true</value>
    </init-param>
   
    <!-- Optional init parameter for refresh-delay option.
    When auto-refresh is true, this init parameter sets the milliseconds of automatic refreshing interval.
    By default, this option is set to 60000 milliseconds (a minute). -->
    <init-param>
      <name>refresh-delay</name>
      <value>60000</value>
    </init-param>
    
    <!-- Optional init parameter for script preferences validator path -->
    <init-param>
      <name>validator</name>
      <!--
       Note: You can set script preferences validator source in three ways. 
       The first is to use context relative path,
       the second is to use file: url, 
       and the third is to classpath: uri.
       Here are the examples for each way.
      -->
      <!--
       <value>/WEB-INF/groovy/HelloGroovyPrefsValidator.groovy</value>
       <value>file:/C:/Program Files/Tomcat/webapps/demo/WEB-INF/groovy/HelloGroovyPrefsValidator.groovy</value>
       <value>classpath:org/apache/portals/bridges/script/HelloGroovyPrefsValidator.groovy</value>
      -->
      <value>classpath:org/apache/portals/bridges/script/HelloJythonPrefsValidator.py</value>
    </init-param>
   
    <!-- The followings are not special for ScriptPortlet, but normal configurations for a portlet. -->
    <supports>
      <mime-type>text/html</mime-type>
      <portlet-mode>VIEW</portlet-mode>
      <portlet-mode>EDIT</portlet-mode>
      <portlet-mode>HELP</portlet-mode>
    </supports>
    <supported-locale>en</supported-locale>
    <portlet-info>
      <title>Hello Jython</title>
      <short-title>Hello Jython</short-title>
      <keywords>demo,jython</keywords>
    </portlet-info>
    <portlet-preferences>
      <preference>
        <name>message</name>
        <value>Hello, Jython!</value>
      </preference>
      <preferences-validator>org.apache.portals.bridges.script.ScriptPortletPreferencesValidator</preferences-validator>
    </portlet-preferences>
   
  </portlet>
 
</portlet-app>

7. Package and deploy the war file to tomcat.

Still checking if this Jython portlet thing works in 2021. So this section can be considered dicey for now. But the first 2 sections are good to go.

References:Reference:

Good Bye ! Stay Safe ! and Stay Hands On!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: