Thursday, 31 March 2016

How to access Portal and Custom Service(Portlet) in Velocity Template (.vm) file

Accessing a custom service / liferay service would be essential specially if you are dealing with the .vm file in Theme / Template (Webcontent)

 There are four simple steps to access service inside .vm file:

1)    Changes in portal-ext.properties
2)    Modify .vm file to access portal service
3)    Modify .vm file to access portlet (custom service)
4)    Verify

Here are the steps in detail:

1)    Changes in portal-ext.properties

To access service we need to use the velocity custom field called "serviceLocator" but by default we can not use service inside .vm file.
as "serviceLocator" variable is restricted to use in .vm file

Here is the default configuration of the liferay inside portal-impl/src/portal.properties

    #
    # Set a comma delimited list of variables the Velocity engine cannot
    # have access to. This will affect Dynamic Data List templates, Journal
    # templates, and Portlet Display templates.
    #
    velocity.engine.restricted.variables=serviceLocator


To enable use of "serviceLocator" below line need to be placed inside porta-ext.properties file.

    velocity.engine.restricted.variables=
   
2)    Modify .vm file to access portal service

Lets say if I want to find company id of one of the existing webcontent ("JournalArticle") then here is the code I may write. Service provided by Liferay OOTB (Out of the Box)

#set ($customLocalService = $serviceLocator.findService('com.liferay.portlet.journal.service.JournalArticleLocalService'))
$customLocalService
Company Id : $customLocalService.getArticle(22214).getCompanyId();



3)    Modify .vm file to access portlet (custom service)

Lets say I have my own portlet called "student-service-portlet" and I like to access name of student having student id "45" then here is the code I would write.

#set ($customLocalService1 = $serviceLocator.findService('student-service-portlet','com.myschool.entities.service.StudentLocalService'))
$customLocalService1
Student Name is : $customLocalService1.getStudentById(45).getName();


4)    Verify

To verify our functionality we will make use of Webcontent , Structure, Template.

Just create one web content with one dummy structure and a template associated to it.
Select the language of Template as "Velocity (.vm)" and paste the code written in step #2 / #3
Save Webcontent and add "Web Content Display" portlet and select the newly created webcontent in it.

On screen you will see the output as

com.liferay.notifications.hook.service.impl.JournalArticleLocalServiceImpl@5e7eb702 Company Id : 20155; com.myschool.entities.service.impl.StudentLocalServiceImpl@49a78571 Student Name is : Henal;

We are done!

Cheers!
Henal Saraiya

Tuesday, 22 March 2016

How to Create a Liferay Application Startup Event Hook

How to Create a Liferay Application Startup Event Hook

Many a times I have seen that application needs to have a lot of configuration, doing all such configuration manually is time consuming job at the same time its tedious too. Fortunately Liferay provides a way to get configuration done grammatically and get rid of manual configuration. Application Startup Event Hook is useful for writing a configuration logic related to configuration of the system.

Here are the simple steps for creating the Application Startup Event Hook
1    Create a Hook "{startupaction}"
2    Create a custom class / action to be executed for configuration
3    Create a properties file for a Hook
4    Map properties file entry with "liferay-hook.xml"
5    Deploy "{startupaction}" hook
6    Test functionality

Here are the steps in detail
1    Create a Hook "{startupaction}"

    To create a hook from command prompt follow below commands:
    i)    Go to your liferay plugin sdk / hooks
    ii)    Fire a command on command propmpt called e:/lifera.../hook>create startupaction "startupaction"

2    Create a custom class / action to be executed for configuration

    Custom Action class which we create will be executed (run method) at the time of deploying our {startupaction} hook
    Lets say we create a Class/Action called "MyStartUpAction" which is used to create a custom field of an organization called "orgType".
    Here is the sample code for

        package com.startup.action;

        import java.util.List;

        import com.liferay.portal.kernel.events.ActionException;
        import com.liferay.portal.kernel.events.SimpleAction;
        import com.liferay.portal.kernel.exception.PortalException;
        import com.liferay.portal.kernel.exception.SystemException;
        import com.liferay.portal.kernel.util.UnicodeProperties;
        import com.liferay.portal.model.Company;
        import com.liferay.portal.model.Role;
        import com.liferay.portal.model.User;
        import com.liferay.portal.security.auth.PrincipalThreadLocal;
        import com.liferay.portal.security.permission.PermissionChecker;
        import com.liferay.portal.security.permission.PermissionCheckerFactoryUtil;
        import com.liferay.portal.security.permission.PermissionThreadLocal;
        import com.liferay.portal.service.CompanyLocalServiceUtil;
        import com.liferay.portal.service.RoleLocalServiceUtil;
        import com.liferay.portal.service.UserLocalServiceUtil;
        import com.liferay.portlet.expando.model.ExpandoBridge;
        import com.liferay.portlet.expando.model.ExpandoColumnConstants;
        import com.liferay.portlet.expando.util.ExpandoBridgeFactoryUtil;

        public class MyStartupAction extends SimpleAction {
            /*
             * (non-Java-doc)
             *
             * @see com.liferay.portal.kernel.events.SimpleAction#SimpleAction()
             */
            public MyStartupAction() {
                super();
            }

            /*
             * (non-Java-doc)
             *
             * @see com.liferay.portal.kernel.events.SimpleAction#run(String[] arg0)
             */
            public void run(String[] companyId) throws ActionException {
                // TODO Auto-generated method stub

                System.out.println("Length of arguments " + companyId.length + " value is " + companyId[0]);
                System.out.println("My Startup Action Method has been called..... !!!");
               
                //We like to create a custom field for the resourceType as "organization".
                String modelResource = "com.liferay.portal.model.Organization";
                long resourcePrimKey = 0;
                String name = "orgType";

                ExpandoBridge expandoBridge = ExpandoBridgeFactoryUtil
                        .getExpandoBridge(Long.parseLong(companyId[0]), modelResource,
                                resourcePrimKey);

                UnicodeProperties properties = null;
                try {
                    properties = expandoBridge.getAttributeProperties(name);
                } catch (Exception e) {
                    properties = new UnicodeProperties();
                }

                //Creating a default property for the "orgType" custom field
                int type = ExpandoColumnConstants.STRING;
                properties.setProperty(ExpandoColumnConstants.PROPERTY_HEIGHT, "105");
                properties.setProperty(ExpandoColumnConstants.PROPERTY_WIDTH, "450");

                //This is a mimic to set a custom permission checker. If we dont set this then while adding a new attribute in expando will create a permission checker error. Piece of code from DoAsUserThread class
                setPermissionChecker(companyId);

                try {
                    expandoBridge.addAttribute(name, type);
                } catch (PortalException e) {
                }
                expandoBridge.setAttributeProperties(name, properties);
            }
           
            /*
                Setting up the custom permission checker object
            */
            private void setPermissionChecker(String[] companyId) {
                Company companyqq = null;
                try {
                    companyqq = CompanyLocalServiceUtil.getCompanyById(Long.parseLong(companyId[0]));
                } catch (PortalException | SystemException e1) {
                }
                Role adminRole = null;
                try {
                    adminRole = RoleLocalServiceUtil.getRole(companyqq.getCompanyId(),"Administrator");
                } catch (PortalException | SystemException e1) {
                }
                List<User> adminUsers = null;
                try {
                    adminUsers = UserLocalServiceUtil.getRoleUsers(adminRole.getRoleId());
                } catch (SystemException e1) {
                }

                PrincipalThreadLocal.setName(adminUsers.get(0).getUserId());
                PermissionChecker permissionChecker = null;
                try {
                    permissionChecker = PermissionCheckerFactoryUtil.create(
                            adminUsers.get(0), true);
                } catch (Exception e1) {
                }
                PermissionThreadLocal.setPermissionChecker(permissionChecker);
            }
        }

   
3    Create a properties file for a Hook

    Create a properties file lets say "portal.properties" in our case on the location   
    liferay-plugins-sdk-6.2\hooks\{startupaction}-hook\docroot\WEB-INF\src\portal.properties
   
    Inside the "portal.properties" file add an entry as below of our custom class / action i.e. MyStartupAction in our case
    application.startup.events=com.startup.action.MyStartupAction

   
4    Map properties file entry with "liferay-hook.xml"

    We need to specify the name of the property file inside the "liferay-hook.xml" file. This is the file which Liferay hook will read for all the overridden properties
   
    Here is the sample entry of "liferay-hook.xml"
    <?xml version="1.0"?>
    <!DOCTYPE hook PUBLIC "-//Liferay//DTD Hook 6.2.0//EN" "http://www.liferay.com/dtd/liferay-hook_6_2_0.dtd">

    <hook>
        <portal-properties>portal.properties</portal-properties>
    </hook>

   
5    Deploy "{startupaction}" hook
   
    Alright Then! We are done with our coding / changes for application startup action hook. Just deploy our hook via below command

    i)    Open command Prompt and go to the location of your plugin sdk and hit "ant"
    ii)    e:\...\liferay-plugins-sdk-6.2\hooks\{startupaction}-hook>ant
   
6    Test functionality

Once we deploy our {startupaction} hook in the console we can see below entries which is the proof that our hook is invoked and our custom
field will be created called "orgType" under "organization".







Console Output is:
Length of arguments 1 value is 20155
My Startup Action Method has been called..... !!!


To verify from the Admin console follow below steps

1)    Go to "Admin" -> "Control Panel"
2)    Go to "Configuration" -> "Custom Fields"
3)    Go to "Organization" -> "Edit"
4)    See our newly created custom field called "orgType" is created and available in listing

Great! We are done!

Cheers!
Henal Saraiya