Saturday, September 5, 2015

Java Reflection in Liferay

Reflection is the way of examining/modifying runtime the behaviour of the class at run time.
Reflection make the possibility of inspect the classes, methods, fields, interfaces without knowing the class names at compile time. We can also instantiate the class and invoke methods at run time.

Generally application development we can create object for class that is available in current class path or server class path means class should be available in the classes directory of your web application or it should be in web application lib directory or it should be in sever lib directory then only we can create object and then invoke methods.

Generally In the server we may have deployed different application and each application is different context and the classes or jar available in each context not shareable to each other until we place these jar files in the server lib directory.

Each web application related jar file we cannot place in server lib directory because until jar file common to all application then it’s good to place in server lib.

Some time we may have minimal need to invoke the methods of the class and the class not available in the current application class loader and it might be available in the other application context.

We have two ways

We need make the jar file available to the required application class path or class loader.
We can use Reflection API to achieve the requirement.

We need make the jar file available to the required application class path or class loader

We just take other application jar file and place into current application lib directory so that we can instantiate object and invoke methods but this not recommended for minimal usage and when we change some implementation in the class again we need update the jar file and place into the current application lib directory.

Reflection API

JAVA Reflection API is good way to instantiate and invoke the methods even though class not available in the current class loader or current class path.

Liferay Class Loaders

Liferay we have different class loader.

Liferay Global Class Loader
Portal Class Loader.
Portlet Class Loader

Liferay Global Class Loader

Liferay Global Class Loader will load the all jar files and make the classes available to entire Liferay portal and we can use these classes anywhere like portal development and plugins development. Generally these jars available in tomacat/lib/ext path and the important jar is portal-service.jar. All these classes will be loaded by Liferay Global Class Loader.

Portal Class Loader

Portal Class loader load all Liferay implementation classes and these classes available in the portal development and all jars available in the ROOT/WEB-INF/lib will be loaded by Portal Class Loader.

Portlet Class Loader

In Liferay development each plugin portlet have its own class loader that is portlet class loader and these class loader make the available to within the portlet and these jars available in PortletName/WEB-INF/lib

In Liferay Portlet development we may have following scenarios when we develop Liferay Plugins Portlet Development.

Using the classes in the Liferay Global Lib
Using Classes in the Portal Class loader
Using classes which are in other plugin Class Loader.

Using the classes in the Liferay Global Lib

In the Liferay development we cannot get any issues to use classes in global class loader and we can instantiate the object and invoke the methods.

Using Classes in the Portal Class loader

Portal class loader classes not available to plugin portlet so in this case we have use reflection API

Using classes which are in other plugin Class Loader.

One plugin portlet classes are not available to other plugin portlet so we need reflection API.

Note:

When we develop hook plugin, EXT plugins then all class loaders are available so we don’t get any issues.

Sharing Service Layer between to Plugin Portlets

Liferay have given way to share service layer between to plugin portlet so we don’t have any issues in the calling services between two plugin contexts.


In the dynamic query API we have provision to load portal class loader classes which are related to service layer using Porta Class loader and also we have portlet class loader.

If the scenario which not belongs to above then we will use Reflection API in Liferay call other class methods which are in different class loaders.

Reflection API using Portal Level classes

Liferay have implemented the Reflection API and we use the following util classes to invoke methods which are in different class loaders


ClassResolverUtil
PortalClassInvoker
PortletClassInvoker


Step: 1

We need to create method and here we will specify the required class, required method to invoke and it parameters types.

If objects then we will use as follows to parameters types in the reflection

Object
Declared in Reflection Method Key
String
String.class
Long
Long.class
Student
Student.class
User
User.class

Primitive Types
Declared in Reflection Method Key
int
Integer.TYPE
long
Long.TYPE


Primitive array Types
Declared in Reflection Method Key
new long[]{  }
long[].class
new int[]{  }
int[].class


Example to create method key for portal level class


MethodKey liveUsersDeleteGroup = 
newMethodKey(ClassResolverUtil.resolveByPortalClassLoader(
"com.liferay.portal.liveusers.LiveUsers"),
"deleteGroup", new Class[] { Long.TYPE, Long.TYPE });



MethodKey leaveGroup = new MethodKey(
ClassResolverUtil
.resolveByPortalClassLoader("com.liferay.portal.liveusers.LiveUsers"),
"leaveGroup", new Class[] { Long.TYPE, Long.TYPE, long[].class });


Method Key need three Parameters i.e. Class Name with class loader type, Method Name and Type of the parameters as Object Array

Step: 2

Now we need to invoke the method with passing required parameter values. We will use invoke method on PortalClassInvoker and it will take method key object and parameter values as object array. Make sure the order of parameters that we declared in the MethodKey object creation.

Syntax:


Class:

PortalClassInvoker

Method:

public static Object invoke(boolean newInstance, MethodKey methodKey, Object... arguments)


Example Usage


PortalClassInvoker.invoke(true, liveUsersDeleteGroup, new Object[] {
themeDisplay.getCompanyId(), deleteGroupId });



PortalClassInvoker.invoke(true, leaveGroup, new Object[] {
themeDisplay.getCompanyId(), groupId, removeUserIdsLong });


If the Original method return some values then we will get it as Object when we invoke through the Reflection call.

Note:

 Parameter types and order we need to make sure.

Complete Example:


<%
long companyId=themeDisplay.getCompanyId();
String portalLevelClassName="com.liferay.portal.liveusers.LiveUsers";
String requiredPortalLevelMthodName="getSessionUsers";
Class[] parameterTypePortalArray={Long.TYPE};
Object[] valuesPortalArray={companyId};
MethodKey getSessionUsers = new MethodKey(ClassResolverUtil.resolveByPortalClassLoader(portalLevelClassName),
requiredPortalLevelMthodName,parameterTypePortalArray);
Object sessionUsersObject=PortalClassInvoker.invoke(true,getSessionUsers,valuesPortalArray);
out.println("sessionUsersObject:<br/>"+userObject);

%>



Reflection API using Portlet Level classes

Assume we have Plugin PortletA and Plugin PortletB we want invoke some methods which are in PortletA from PortletB

Portlet Context:  PortletA-portlet

Finding Portlet Context.



Portlet Id: PortletA_WAR_PortletAportlet

Finding Porttet Id

Go portlet Maximized window state from portlet configuration


Find Portlet id from requested URL


We have implemented some Util class and methods in Plugin PortletA as follows


package com.meera.portleta.util;
import com.liferay.portal.kernel.exception.PortalException;
import com.liferay.portal.kernel.exception.SystemException;
import com.liferay.portal.model.User;
import com.liferay.portal.service.UserLocalServiceUtil;
public class PortletAUtil {
public static User getUser(long userId) throws PortalException, SystemException {
return UserLocalServiceUtil.getUser(userId);
}
public static String  getMessage(String message){
return "Hi Meera syas" +message;
}
}


Now we will invoke PortletA method from PortletB

Step: 1

Create MethodKey Object


MethodKey getUser = new MethodKey(ClassResolverUtil.resolveByPortletClassLoader(className,portletContext),
requiredMthodName,parameterTypeArray);



Step: 2

Invoke method using PortletClassInvoker

Syntax


Class:

PortletClassInvoker

Method:

public static Object invoke(boolean newInstance, String portletId, MethodKey methodKey,Object... arguments)


Example Code in PortletB JSP  page.


<h4>1:PortletB invoking method which is in Portlet A class Loader Using Reflection</h4>
<%
long userId=themeDisplay.getUserId();
String className="com.meera.portleta.util.PortletAUtil";
String portletContext="PortletA-portlet";
String requiredMthodName="getUser";
Class[] parameterTypeArray={Long.TYPE};
Object[] valuesArray={userId};
String portletId="PortletA_WAR_PortletAportlet";
MethodKey getUser = new MethodKey(ClassResolverUtil.resolveByPortletClassLoader(className,portletContext),
requiredMthodName,parameterTypeArray);
Object userObject=PortletClassInvoker.invoke(true,portletId,getUser,valuesArray);
out.println("userObject:<br/>"+userObject);
%>


Note:

In the above example we implemented method in the PortletA plugin context and we are invoking in PortletB JSP page.


Complete Code Example Calling Methods from Portal and Portlet Level class loader classes.

View.jsp in PortletB


<%@page import="com.liferay.portal.kernel.util.PortalClassInvoker"%>
<%@page import="com.liferay.portal.kernel.util.PortletClassInvoker"%>
<%@page import="com.liferay.portal.kernel.util.ClassResolverUtil"%>
<%@page import="com.liferay.portal.kernel.util.MethodKey"%>
<%@page import="java.util.Map"%>
<%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet" %>
<%@ taglib uri="http://liferay.com/tld/aui" prefix="aui" %>
<%@taglib uri="http://liferay.com/tld/portlet" prefix="liferay-portlet" %>
<%@taglib uri="http://liferay.com/tld/security" prefix="liferay-security" %>
<%@taglib uri="http://liferay.com/tld/theme" prefix="liferay-theme" %>
<%@taglib uri="http://liferay.com/tld/ui" prefix="liferay-ui" %>
<%@taglib uri="http://liferay.com/tld/util" prefix="liferay-util" %>
<portlet:defineObjects />
<liferay-theme:defineObjects />

<h4>1:PortletB invoking method which is in Portlet A class Loader Using Reflection</h4>
<%
long userId=themeDisplay.getUserId();
String className="com.meera.portleta.util.PortletAUtil";
String portletContext="PortletA-portlet";
String requiredMthodName="getUser";
Class[] parameterTypeArray={Long.TYPE};
Object[] valuesArray={userId};
String portletId="PortletA_WAR_PortletAportlet";
MethodKey getUser = 
new MethodKey(ClassResolverUtil.resolveByPortletClassLoader(className,portletContext),
requiredMthodName,parameterTypeArray);
Object userObject=PortletClassInvoker.invoke(true,portletId,getUser,valuesArray);
out.println("userObject:<br/>"+userObject);
%>
<h4>2:PortletB invoking method which is in Portal class Loader Using Reflection</h4>
<%
long companyId=themeDisplay.getCompanyId();
String portalLevelClassName="com.liferay.portal.liveusers.LiveUsers";
String requiredPortalLevelMthodName="getSessionUsers";
Class[] parameterTypePortalArray={Long.TYPE};
Object[] valuesPortalArray={companyId};
MethodKey getSessionUsers = 
new MethodKey(ClassResolverUtil.resolveByPortalClassLoader(portalLevelClassName),
requiredPortalLevelMthodName,parameterTypePortalArray);
Object sessionUsersObject=PortalClassInvoker.invoke(true,getSessionUsers,valuesPortalArray);
out.println("sessionUsersObject:<br/>"+userObject);
%>


Download Liferay Reflection Example


Usage of Portlets

Download Liferay Reflection Example from above link you can find war files and source code you can directly place war files in portlet deploy directory then it will be deployed.
Now drag and drop PortletB in the page then you can see sample output.

Note:


Portlet have developed in Liferay 6.2 CE GA4 so based on your version you can build it from source that I have given.

PortletB View shows Example out put

Author

Popular Posts

Recent Posts

Recent Posts Widget