Friday, February 12, 2016

Ajaxable Search Container Liferay

Ajaxable Search Container Liferay
Objective:  we are going to create a portlet which lists all the Liferay portal user using liferay-ui search container and making it ajaxable.
Here we are going to use liferay 6.2 EE (you can do it with CE as well) and inbuilt Alloy AUI JS .
Here I am starting with creating portlet and so on so if you are interested in knowing the magic code which makes it ajaxable then move to step 4.
Step 1

                Create a liferay plugin project  with name AjaxSearchContainer . so you will have one portlet entry in portlet.xml , change the view-template parameter to /html/ajaxsc/view.jsp.  Now Create an action class com.liferay.ajaxsc.UserListAction which extends MVCPortlet. 


Note: This step is intended for users who want to create same example which I am explaining here. So if you have any confusions in creating liferay plugin project you can go through the respective examples.

Step 2

            Now create init.jsp file to keep all you imports at one place and include it inside your view.jsp and also create  user_list.jsp file which will contain our search container.


Step 3

Concept: Here from our view.jsp we have created a div which will contain the dynamically loaded searchcontainer. On document ready we are making an ajax call which will hit the serveResource method in our Action Class and there we will prepare the SearchContainer object with results, delta etc and will set searchContainer object in request attribute and will  include user_list.jsp . In out user_list.jsp we will get that searchContainer object which will be used to populate Records.

Now  inside our view.jsp we  have created a div which will contain our searchcontainer . After  that we are doing an ajax call  which will be invoked on document ready i.e from aui ready context and ajax call will invoke searveResource Method   Below is the code. Here you can see in aui ready we are including two aui modules aui-base and aui-io-plugin-deprecated.
<%@ include file="init.jsp"%>
<portlet:resourceURL var="loadUsers"></portlet:resourceURL>
<div id="<portlet:namespace/>userList">
</div>
<aui:script>
AUI().ready('aui-base', 'aui-io-plugin-deprecated',function(A) {

            var userListCon = A.one('#<portlet:namespace/>userList');
            if(userListCon) {
                        userListCon.plug(
            A.Plugin.IO,
            {
                autoLoad: false
            }
        );
                        console.log("calling resource..")
                        userListCon.io.set('uri', "<%=loadUsers%>");
                userListCon.io.start();
            }          
});
</aui:script>

Step 4
            In our action class we are getting two parameters cur and delta where cur is current page and delta is items per page. In first call we will not have these parameters available so it will have default values current page 1 and delta 5. After that we are creating iteratorURL and After that we are creating SearchContainer Object with all necessary parameters. And ultimately setting that search container as request Attribute. Here is the code..

package com.liferay.ajaxsc;

import com.liferay.portal.kernel.dao.search.SearchContainer;
import com.liferay.portal.kernel.exception.SystemException;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.portlet.LiferayWindowState;
import com.liferay.portal.kernel.util.ParamUtil;
import com.liferay.portal.model.User;
import com.liferay.portal.service.UserLocalServiceUtil;
import com.liferay.util.bridges.mvc.MVCPortlet;

import java.io.IOException;
import java.util.List;

import javax.portlet.PortletException;
import javax.portlet.PortletURL;
import javax.portlet.ResourceRequest;
import javax.portlet.ResourceResponse;

public class UserListAction extends MVCPortlet{
            Log _log = LogFactoryUtil.getLog(UserListAction.class.getName());


            @Override
            public void serveResource(ResourceRequest resourceRequest,
                                    ResourceResponse resourceResponse) throws IOException,
                                    PortletException {
                        _log.info("Getting Users..");
                        int cur = ParamUtil.getInteger(resourceRequest, "cur", 1);
                        int delta = ParamUtil.getInteger(resourceRequest, "delta", 5);
                        _log.info("cur: " + cur);
                        _log.info("delta: " + delta);
                        PortletURL iteratorURL = resourceResponse.createRenderURL();
                        iteratorURL.setWindowState(LiferayWindowState.NORMAL);
                       
                        SearchContainer<User> userListSearchContainer = new SearchContainer<User>(
                                                resourceRequest, null, null, "cur", cur, delta,
                                                iteratorURL, null, "No Users found.");
                        List<User> users = null;
                        int total = 0;
                        try {
                                    users = UserLocalServiceUtil.getUsers(userListSearchContainer.getStart(), userListSearchContainer.getEnd());
                                    total = UserLocalServiceUtil.getUsersCount();
                        } catch (SystemException e) {
                                    _log.error(e.getLocalizedMessage());
                        }
                       
                        userListSearchContainer.setResults(users);
                        userListSearchContainer.setTotal(total);
                        resourceRequest.setAttribute("userListSearchContainer", userListSearchContainer);
                        include("/html/ajaxsc/user_list.jsp", resourceRequest, resourceResponse);
                       
            }

}

In the above code we are including user_list.jsp.  So our search container will be available there as a request attribute.

Step 5
            In user_list.jsp we are getting that searchcontainer object from request attribute and populating searchcontainer.  For using liferay SearchContainer we have to import liferay-ui taglib which we have included in init.jsp as below

<%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet" %>
<%@ taglib uri="http://liferay.com/tld/ui" prefix="liferay-ui" %>
<%@ taglib uri="http://alloy.liferay.com/tld/aui" prefix="aui" %>
<portlet:defineObjects/>
<style scoped="scoped">

div.lfr-pagination-config {

display:none;
}
</style>
Now In final step we have to write Script which will help in pagination to work without refresh.
Here is our user_list.jsp

<%@page import="com.liferay.portal.kernel.dao.search.SearchContainer"%>
<%@page import="java.util.Enumeration"%>
<%@page import="com.liferay.portal.service.UserLocalServiceUtil"%>
<%@page import="com.liferay.portal.kernel.util.ParamUtil"%>
<%@page import="com.liferay.portal.model.User"%>
<%@page import="java.util.List"%>
<%@ include file="init.jsp"%>
<%
SearchContainer userListSearchContainer = (SearchContainer)request.getAttribute("userListSearchContainer");

%>
<liferay-ui:search-container searchContainer="<%=userListSearchContainer %>">
     <liferay-ui:search-container-results />
           <liferay-ui:search-container-row className="com.liferay.portal.model.User" modelVar="userModel">
                <liferay-ui:search-container-column-text name="Name" value="<%=userModel.getFullName() %>"></liferay-ui:search-container-column-text>
                <liferay-ui:search-container-column-text name="Email" value="<%=userModel.getEmailAddress()%>"></liferay-ui:search-container-column-text>
           </liferay-ui:search-container-row>
     <liferay-ui:search-iterator paginate="<%= true %>" />
</liferay-ui:search-container>

<aui:script use="aui-base,aui-io-plugin-deprecated">
   
    var userListContainer = A.one('#<portlet:namespace/>userList');
    var paginator = userListContainer.all('.taglib-search-iterator-page-iterator-bottom,.taglib-search-iterator-page-iterator-top,.lfr-pagination-page-selector,.lfr-pagination-delta-selector');

    if (userListContainer) {
        var parent = userListContainer;
        parent.plug(
            A.Plugin.IO,
            {
                autoLoad: false
            }
        );
        paginator.all('a').on(
            'click',
            function(event) {
                event.preventDefault();

                var uri = event.currentTarget.get('href');
                    
                     if(window.console && window.console.log) {
                    
                           console.log('original uri:', uri, event.currentTarget);
                     }   
               
                if (uri != 'javascript:;') {
                     uri = event.currentTarget.get('href').replace(/p_p_lifecycle=0/i, 'p_p_lifecycle=2');                 
                     if(window.console && window.console.log) {
                    
                         console.log('altered uri:', uri);
                         }

                     parent.io.set('uri', uri);
                     parent.io.start();
                 }
            }
        );
    }
</aui:script>


In the above javascript we are getting out container which we have created in view.jsp then we are getting all paginators inside that with their class . After that we have plugged the Input/output component with our container. Now we have bind click  event on pagination . So when user clicks on pagination we are replacing lifecycle value from 0 to 2 where 0 is for render phase and 2 is for resource phase so with this our pagination becomes  resource serving urls and they will invoke the serve resource method of our action class. Same process will repeat.


Note: you can see in init.jsp we have kept
                        

This will make our left side paginators hidden. Because this implementation is not supporting left side pagination.


Now we are done with all necessary steps we will check results

You can see the ajax loader clicking on next.
Hope this helps Thanks.

Sunday, February 7, 2016

Liferay Custom Portlets Plugin Project

Environment:
Liferay 6.2
Liferay Tomcat 7

In this blog we will see how  to  create liferay  project of portlet plugin type,  and inside that project  how to create  liferay mvc portlet plugin. In one project  we can create ,more than one portlets plugin.

Creating liferay mvc portlet:

Step 1: In eclipse click on new liferay project from dropdown option as shown in below screen.


Step 2:  Give project name , in this example name is  “Sampleproject” and in build type select Ant(liferay plugin sdk)  as in this example we are using ant, after plugin type field there is one checkbox (include sample code) uncheck that field, if we check that field during project creation then one default portlet with project name will be created, as shown in below screen and click next

Step 3: Select liferay mvc , as shown in below screen, then click finish

Step 4: Now project  is created, below screen represents project folder structure.

Step 5: Now we will create portlet inside “Sampleproject”  project which we have created in above steps.
Right click on “Sampleproject” àNewàclick on  liferay portlet

Step 6: Give portlet Class/controller name, in this example class name is “Employeemanage” , java package is “com.test”, click next.

Step 7: Below screen represents portlet info like:  Name, Display name,Title, Portlet mode etc. Click next.

Step 8: Below screen represents Display category selected value, based on selected value after deployment portlet  will be available in that category, in this example selected value is Sample.
Click next.

Step 9 : Click Finish.

Step 10: Below screen represents  folder structure of created portlet    “Employeemanage”  inside “Sampleproject-portlet”  project.

Step 11:  Liferay project of portlet plugin type and inside that one liferay mvc custom portlet is created , now will see how to deploy this project.
Right click on project “Sampleproject-portlet”àliferayàsdkàdeploy 


Step 12: After deployment, go to your liferay  portal local url, in this example url is localhost:8080.If you are not logged in then logg in with your portal admin account, in this example admin account email :test@liferay.com  ,  pass: test
From left side menu click on add(+) .As shown in below screen.

Step 13:  In sample display category we can see that our created portlet  “Employeemanage”  is available, click on add link to add this portlet on portal page.

Step 14: In below screen we can see now our portlet  “Employeemanage” is added on portal page.



Liferay Service Builder Basic Concept

Environment :
Liferay 6.2
Liferay Tomcat 7

Liferay Service Builder is a tool built by liferay that allows developers to define entities. It  generates necessary model , persistence and  service layers for our applications. It uses spring and hibernate internally to generate set of  classes, sql scripts and configuration files to interact with database. It takes service.xml file as input and generate the set of classes and interfaces to interact with Database. Using this service layers we can interact with database and can perform CRUD operation( operation like ->Add,update,delete,retrieve). The service builder tool takes xml file (its called service.xml) as an input and generate code based on the input provided in service.xml.

STEPS:
Step1: Create one liferay mvc project of portlet plugin type and one portlet inside that project.

Step 2: Create service.xml file using liferay ide,


While creating service.xml select plugin project for which we are creating service.xml , in this example project : Sampleproject, package path:com.slayer(path contain service related files), Namespace : X, follow below screen. Click finish.

Step 3: Define required entities/tables in service.xml, Created service.xml contain sample entity definition, we will edit/add as per requirement, in this example below is service.xml content.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE service-builder PUBLIC "-//Liferay//DTD Service Builder 6.2.0//EN" "http://www.liferay.com/dtd/liferay-service-builder_6_2_0.dtd">
<service-builder package-path="com.slayer">
       <author>samsun</author>
       <namespace>X</namespace>

       <entity name="EmployeeManage" local-service="true" remote-service="false">

              <!-- PK fields -->
              <column name="employeeId" type="long" primary="true" />

              <column name="empFirstName" type="String" />
              <column name="empLastName" type="String" />
              <column name="empAge" type="int" />
              <column name="empNumber" type="String" />
       </entity>
</service-builder>

Step 4: Run the service builder: Once we created service.xml and defined entity detail, now we need to  run service builder. We can run the service builder in eclipse from ANT view. We need to click on build-service target from the ANT view.
Click on Sampleproject-portlet in which we have created service.xml and defined entityàLiferayàBuild Service
Follow below screen:


After successful building service, we will get below successful message:

Below screen shows service builder generated service layers file:

After deployment of project we will notice a new table X_EmployeeManage  got automatically created by liferay when our service layer got deployed to the server. The table name is prefixed with the namespace: X , followed by the actual entity name : EmployeeManage.
Complete entity name: X_EmployeeManage
We can optionally disable this auto-prefix  by specifying   auto-namespace-tables=”false” attribute for “<service-builder>”  tag of the service.xml after package path attribute.
Below screen shows entity/table generated in database:

Export and Import Data from custom Portlet



Liferay has provided an ultimate feature of exporting your data as a file of type lar. Which will contain your data which you would like to export and import to some other place for the same portlet type. Liferay has given this feature for almost all the out of box portlets and also we can implement the same for our custom portlet. Here I am implementing for my custom portlet. Here in this example i am going to show from creating an entity in Service Builder to export it from one site and again importing the data in different site.

Step: 1
            Create a service builder project. 



Step: 2 
          Define an entity inside your service.xml .

Note:  In Liferay 6.2 onwards for an Entity Eligible to Export and Import It should contain following Fields:

These fields are mandatory to any Entity to become an staged Model  , If you will add these fields then your Entity Class will Extend StagedGroupedModel. Then this model will become eligible for Staging and Export/Import. You can check you classes generated to confirm your ModelClass is extending StagedGroupedModel or not. Just go to class named ProductModel  you can see there it will be extending  StagedGroupedModel. And I would like to add that we are folloeing standard approach same as Liferay does for its out ob box portlet . you can import and export your data even if it doesn’t have these fields.


Here is how our service.xml looks

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE service-builder PUBLIC "-//Liferay//DTD Service Builder 6.2.0//EN" "http://www.liferay.com/dtd/liferay-service-builder_6_2_0.dtd">
<service-builder package-path="com.liferay.product.slayer">
     <author>Md Azaz Ali</author>
     <namespace>EI</namespace>

     <entity name="Product" uuid="true" local-service="true" remote-service="false">

           <!-- PK fields -->

           <column name="productId" type="long" primary="true" />

           <!-- Audit fields -->

           <column name="companyId" type="long" />
           <column name="groupId" type="long" />
           <column name="userId" type="long" />
           <column name="userName" type="String" />
           <column name="createDate" type="Date" />
           <column name="modifiedDate" type="Date" />

           <!-- Other fields -->

           <column name="productName" type="String" />
           <column name="Price" type="long" />
           <column name="sku" type="String" />

           <!-- Order -->

           <order by="asc">
                <order-column name="productName" />
           </order>
     </entity>
</service-builder>


Step: 3 
      Creating view.jsp inside folder structure



I have created a form in view.jsp and written a addProduct() method in action class ExportImportPortlet to add Products. Here is view.jsp

<%@page import="javax.portlet.ActionRequest"%>
<%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet" %>
<%@ taglib uri="http://alloy.liferay.com/tld/aui" prefix="aui"%>
<portlet:defineObjects />
<portlet:actionURL var="addProductURL">
     <portlet:param name="<%=ActionRequest.ACTION_NAME %>" value="addProduct"/>
</portlet:actionURL>
<aui:form action="<%=addProductURL %>">
     <aui:input name="productName"></aui:input>
     <aui:input name="sku"></aui:input>
     <aui:input name="price"></aui:input>
     <aui:input name="submit" type="submit" value="submit"></aui:input>
</aui:form>


Here is my action Class

package com.liferay.product.portlet;

import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.util.ParamUtil;
import com.liferay.portal.service.ServiceContext;
import com.liferay.portal.service.ServiceContextFactory;
import com.liferay.product.slayer.model.Product;
import com.liferay.product.slayer.service.ProductLocalServiceUtil;
import com.liferay.util.bridges.mvc.MVCPortlet;

import java.io.IOException;

import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.PortletException;

public class ExportImportPortlet extends MVCPortlet{
            public void addProduct(ActionRequest actionRequest,
                                    ActionResponse actionResponse) throws IOException, PortletException {
                        String productName = ParamUtil.getString(actionRequest, "productName");
                        String sku = ParamUtil.getString(actionRequest, "sku");
                        long price = ParamUtil.getLong(actionRequest, "price");
                        try {
                                    ServiceContext serviceContext = ServiceContextFactory.getInstance(Product.class.getName(), actionRequest);
                                    ProductLocalServiceUtil.addProduct(productName, sku, price, serviceContext);
                        } catch (Exception e) {
                                    _log.error(e);
                        }
            }
            Log _log =  LogFactoryUtil.getLog(ExportImportPortlet.class);
}
In above Action class addProduct method I am using addProduct method of ProductLocalServiceUtil which takes four parameters to add a product Information . Below is the code for method written in ProductLocalServiceImpl classs.
/**
 * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
 *
 * The contents of this file are subject to the terms of the Liferay Enterprise
 * Subscription License ("License"). You may not use this file except in
 * compliance with the License. You can obtain a copy of the License by
 * contacting Liferay, Inc. See the License for the specific language governing
 * permissions and limitations under the License, including but not limited to
 * distribution rights of the Software.
 *
 *
 *
 */

package com.liferay.product.slayer.service.impl;

import com.liferay.portal.kernel.exception.SystemException;
import com.liferay.portal.service.ServiceContext;
import com.liferay.product.slayer.model.Product;
import com.liferay.product.slayer.service.base.ProductLocalServiceBaseImpl;

import java.util.Date;

/**
 * The implementation of the product local service.
 *
 * <p>
 * All custom service methods should be put in this class. Whenever methods are added, rerun ServiceBuilder to copy their definitions into the {@link com.liferay.product.slayer.service.ProductLocalService} interface.
 *
 * <p>
 * This is a local service. Methods of this service will not have security checks based on the propagated JAAS credentials because this service can only be accessed from within the same VM.
 * </p>
 *
 * @author Md Azaz Ali
 * @see com.liferay.product.slayer.service.base.ProductLocalServiceBaseImpl
 * @see com.liferay.product.slayer.service.ProductLocalServiceUtil
 */
public class ProductLocalServiceImpl extends ProductLocalServiceBaseImpl {
            /*
             * NOTE FOR DEVELOPERS:
             *
             * Never reference this interface directly. Always use {@link com.liferay.product.slayer.service.ProductLocalServiceUtil} to access the product local service.
             */
            public Product addProduct(String productName, String sku, long price, ServiceContext serviceContext) throws SystemException {
                        Product product = productPersistence.create(counterLocalService.increment(Product.class.getName()));
                        product.setGroupId(serviceContext.getScopeGroupId());
                        product.setCompanyId(serviceContext.getCompanyId());
                        product.setUserId(serviceContext.getUserId());
                        product.setUserName(userLocalService.fetchUser(serviceContext.getUserId()).getFullName());
                        product.setCreateDate(new Date());
                        product.setModifiedDate(new Date());
                        product.setProductName(productName);
                        product.setSku(sku);
                        product.setPrice(price);
                        productLocalService.addProduct(product);
                        return product;
            }
}

Step: 4

      We will create two sites one named Export Site and add a page.

Drop portlet on page.
So add some record  like





Now add another site with name Import Site and add a page and drop same portlet there. I am not showing scrrenshot for this . you can take reference from previous one. Now we will see The steps which are responsible for Export and Import Process. Step: 5 Now we have to write a class which will extend BaseStagedModelDataHandler and it will override necessary methods. This class will be responsible for writing object to file and retrieving object from file inside exported lar. Here we have created ProductStagedModelDataHandler .


package com.liferay.product.lar;

import com.liferay.counter.service.CounterLocalServiceUtil;
import com.liferay.portal.kernel.exception.PortalException;
import com.liferay.portal.kernel.exception.SystemException;
import com.liferay.portal.kernel.lar.BaseStagedModelDataHandler;
import com.liferay.portal.kernel.lar.ExportImportPathUtil;
import com.liferay.portal.kernel.lar.PortletDataContext;
import com.liferay.portal.kernel.xml.Element;
import com.liferay.portal.service.ServiceContext;
import com.liferay.product.slayer.model.Product;
import com.liferay.product.slayer.service.ProductLocalServiceUtil;

import java.util.Date;

public class ProductStagedModelDataHandler extends BaseStagedModelDataHandler<Product>{

            public static final String[] CLASS_NAMES = {Product.class.getName()};
           
            @Override
            public void deleteStagedModel(String paramString1, long paramLong,
                                    String paramString2, String paramString3) throws PortalException,
                                    SystemException {
            }

            @Override
            protected void doExportStagedModel(
                                    PortletDataContext portletDataContext, Product product)
                                    throws Exception {
                        Element productElement = portletDataContext.getExportDataElement(product);
                        portletDataContext.addClassedModel(productElement, ExportImportPathUtil.getModelPath(product), product);
            }

            @Override
            protected void doImportStagedModel(
                                    PortletDataContext portletDataContext, Product product)
                                    throws Exception {
                        ServiceContext serviceContext = portletDataContext.createServiceContext(product);
                        if (portletDataContext.isDataStrategyMirror()) {
                                    Product existingProduct = ProductLocalServiceUtil.fetchProductByUuidAndGroupId(product.getUuid(), portletDataContext.getGroupId());
                                    if(existingProduct == null) {
                                                product.setProductId(CounterLocalServiceUtil.increment(Product.class.getName()));
                                                product.setGroupId(portletDataContext.getGroupId());
                                                product.setCreateDate(new Date());
                                                product.setModifiedDate(new Date());
                                                ProductLocalServiceUtil.addProduct(product);
                                    } else {
                                                existingProduct.setProductName(product.getProductName());
                                                existingProduct.setPrice(product.getPrice());
                                                existingProduct.setSku(product.getSku());
                                                ProductLocalServiceUtil.updateProduct(existingProduct);
                                    }
                        } else {
                                    product.setProductId(CounterLocalServiceUtil.increment(Product.class.getName()));
                                    product.setGroupId(portletDataContext.getGroupId());
                                    product.setCreateDate(new Date());
                                    product.setModifiedDate(new Date());
                                    ProductLocalServiceUtil.addProduct(product);
                        }
            }
            @Override
            public String getDisplayName(Product product) {
                        return product.getUuid();
            }
            @Override
            public String[] getClassNames() {
                        return CLASS_NAMES;
            }

}


Note:
In the above code we have overridden doExportStagedModel which will recive two parameters portletDataContext and product. Here portletDataContext contains all necessary methods required to export an object and product is the object to be exported.
In the above code we have overridden the method wich is returning array of classNames to be exported and imported.
Now  we have also overrided doImportStagedModel this also recieves same parameters. Here the product object is the from the lar file it means the exported one. So in our case as we are just changing the site we can just change the groupId to the current group and generate new Primarykey and add it to DB . In case you are importing it to different Server or different Instance of same Portal then you have to change company id to current companyId , both groupId and companyId of current place(where we are importing ) is available in portletDataContext object you can see.


Step:  6
            Now we have to provide the Entry of this class in liferay-portlet.xml, keep this tag just below icon tag . Any how I will provide complete file later.

<staged-model-data-handler-class>com.liferay.product.lar.ProductStagedModelDataHandler</staged-model-data-handler-class> 

Step: 7
            Now we have write another class which will extend from BasePortletDataHandler
and  have to override getExportControls , getImportControls , doExportData  and  doImportData.

package com.liferay.product.lar;

import com.liferay.portal.kernel.dao.orm.ActionableDynamicQuery;
import com.liferay.portal.kernel.dao.orm.DynamicQuery;
import com.liferay.portal.kernel.dao.orm.RestrictionsFactoryUtil;
import com.liferay.portal.kernel.exception.SystemException;
import com.liferay.portal.kernel.lar.BasePortletDataHandler;
import com.liferay.portal.kernel.lar.PortletDataContext;
import com.liferay.portal.kernel.lar.PortletDataHandlerBoolean;
import com.liferay.portal.kernel.lar.PortletDataHandlerControl;
import com.liferay.portal.kernel.lar.StagedModelDataHandlerUtil;
import com.liferay.portal.kernel.xml.Element;
import com.liferay.portlet.dynamicdatalists.model.DDLRecordSet;
import com.liferay.product.slayer.model.Product;
import com.liferay.product.slayer.service.persistence.ProductExportActionableDynamicQuery;

import java.util.List;

import javax.portlet.PortletPreferences;

public class ProductPortletDataHandler extends BasePortletDataHandler {
            public static final String NAMESPACE = "product";
            @Override
            public PortletDataHandlerControl[] getExportControls() {
                        PortletDataHandlerBoolean products = new PortletDataHandlerBoolean(NAMESPACE, "Products", true, true);
                        return new PortletDataHandlerControl[]{products};
            }
            @Override
            public PortletDataHandlerControl[] getImportControls() {
                        return getExportControls();
            }
            @Override
            protected String doExportData(PortletDataContext portletDataContext,
                                    String portletId, PortletPreferences portletPreferences)
                                    throws Exception {
                        Element rootElement = addExportDataRootElement(portletDataContext);
                        if(portletDataContext.getBooleanParameter(NAMESPACE, "Products")) {
                                    ActionableDynamicQuery productActionableDynamicQuery = getProductActionableDynamicQuery(portletDataContext);
                                    productActionableDynamicQuery.performActions();
                        }
                        return getExportDataRootElementString(rootElement);
            }
            @Override
            protected PortletPreferences doImportData(
                                    PortletDataContext portletDataContext, String portletId,
                                    PortletPreferences portletPreferences, String data)
                                    throws Exception {
                        if(portletDataContext.getBooleanParameter(NAMESPACE, "Products")) {
                                    Element productsElement =
                                                            portletDataContext.getImportDataGroupElement(
                                                                                    Product.class);
                                   
                                    List<Element> productElements = productsElement.elements();
                                   
                                    for (Element productElement : productElements) {
                                                StagedModelDataHandlerUtil.importStagedModel(
                                                                        portletDataContext, productElement);
                                    }
                                   
                        }
                        return portletPreferences;
            }
            protected ActionableDynamicQuery getProductActionableDynamicQuery(final PortletDataContext portletDataContext) throws SystemException {
                       
                        return new ProductExportActionableDynamicQuery(portletDataContext) {
                                    @Override
                                    protected void addCriteria(DynamicQuery dynamicQuery) {
                                                super.addCriteria(dynamicQuery);
                                                dynamicQuery.add(RestrictionsFactoryUtil.eq("groupId", portletDataContext.getGroupId()));
                                    }
                        };
            }

}

Note:  Here in doExportData method we are adding a root Element  after that we have created getProductActionableDynamicQuery  in which we are adding extra criteria like we have added groupId as we are going to export/import data between sites and after that we are calles performActions method which will internally get the records from db and call the doExportStagedModel in ProductStagedModelDataHandler for every object.
Now In doImportData method we are checking if Products are to be imported and getting Elements for product in which each element represents one Product object . And calling importStagedModel on ProductStagedModelDataHandler . which will import the Data.



Step 8:
            Now we have to Provide the entry of this class in liferay-portlet.xml as below . insert it just above <staged-model-data-handler-class> tag so our final liferay-portlet.xml will be.

<?xml version="1.0"?>
<!DOCTYPE liferay-portlet-app PUBLIC "-//Liferay//DTD Portlet Application 6.2.0//EN" "http://www.liferay.com/dtd/liferay-portlet-app_6_2_0.dtd">

<liferay-portlet-app>
            <portlet>
                        <portlet-name>ExportImport</portlet-name>
                        <icon>/icon.png</icon>
                        <portlet-data-handler-class>com.liferay.product.lar.ProductPortletDataHandler</portlet-data-handler-class>
                        <staged-model-data-handler-class>com.liferay.product.lar.ProductStagedModelDataHandler</staged-model-data-handler-class>
                        <header-portlet-css>/css/main.css</header-portlet-css>
                        <footer-portlet-javascript>/js/main.js</footer-portlet-javascript>
                        <css-class-wrapper>ExportImport-portlet</css-class-wrapper>
            </portlet>
            <role-mapper>
                        <role-name>administrator</role-name>
                        <role-link>Administrator</role-link>
            </role-mapper>
            <role-mapper>
                        <role-name>guest</role-name>
                        <role-link>Guest</role-link>
            </role-mapper>
            <role-mapper>
                        <role-name>power-user</role-name>
                        <role-link>Power User</role-link>
            </role-mapper>
            <role-mapper>
                        <role-name>user</role-name>
                        <role-link>User</role-link>
            </role-mapper>
</liferay-portlet-app>
Step: 9
            Now we are ready with all necessary work needed to Export and Import data from custom portlet . Now we will go to Export Site where we have droped the portlet and added some Data .Now click on gear icon on right side of portlet and click on Export/Import.


Now in below you will see following options  in Three different category Application, Content and Permissions. In content section we have Products and it is checked means it will be exported with the data if you want to skip means don’t want to export Products then you can click on checkbox and simply uncheck it.


Now to export click on export button you will see this. Export is in process…

Now  once it is done you will see this screen.


Now you can download the file and save it. Now if you will open your lar file using any zip extractor like 7 Zip you can see your  data there. Once you ope n your lar file move to

\ExportImport-201602070547.portlet.lar\group\10181\portlet\ExportImport_WAR_ExportImportportlet\10184\


You will see two folders  portlet-data.xml and portlet.xml.



You can see data exported  .

Step: 10
            Now go to import site where we have droped same portlet  Now here also go to gear icon and click on Export/Import 






Now you will see success message. So to confirm data is imported just go to DB and check the records


Here you can see highlighted records which are imported from lar file . As you can see groupId and primaryKey is different. So we are done with Export Import Feature of Liferay. For Further advanced Features you can comment on this .