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 PortletAplugin 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 GA4so based on your version you can build it from source that I have given.
PortletB View shows Example out put
Author
0 comments:
Post a Comment