Thursday, August 6, 2015

Steps to add workflow into custom portlet:


Need to use following steps to add workflow into cusotm portlet:

1. Create a liferay project (e.g. CustomWorkflowPortlet)
3. Create a service.xml file write following code:



<?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.custom.workflow.service">
<author>A0683741</author>
<namespace>custom_workflow</namespace>
<entity name="CustomWorkflow" table="CustomWorkflow" local-service="true" remote-service="true">
<!-- PK fields -->
<column name="workflowId" type="long" primary="true" />
<!-- Audit fields -->
<column name="customId" type="long" />
<column name="companyId" type="long" />
<column name="userId" type="long" />
<column name="groupId" type="long" />
<column name="userName" type="String" />
<column name="createDate" type="Date" />
<column name="modifiedDate" type="Date" />
<!-- Workflow fields -->
<!-- Resource -->
<column name="resourcePrimKey" type="long"></column>
<column name="title" type="String"></column>
<column name="status" type="int"></column>
<column name="statusByUserId" type="long"></column>
<column name="statusByUserName" type="String"></column>
<column name="statusDate" type="Date"></column>
<!-- Finder methods -->
<finder name="ResourcePrimKey" return-type="CustomWorkflow">
<finder-column name="resourcePrimKey"></finder-column>
</finder>
<finder name="Status" return-type="Collection">
<finder-column name="status"></finder-column>
</finder>
<finder name="R_S" return-type="CustomWorkflow">
<finder-column name="resourcePrimKey"></finder-column>
<finder-column name="status"></finder-column>
</finder>
<!-- end of workflow columns and finders -->
<finder return-type="Collection" name="customId">
<finder-column name="customId"></finder-column>
</finder>
<reference package-path="com.liferay.portal" entity="WorkflowInstanceLink"></reference>
<reference package-path="com.liferay.portlet.asset" entity="AssetEntry"></reference>
<reference package-path="com.liferay.portlet.social" entity="SocialActivity"></reference>

</entity>
</service-builder>




3. Build the service and 
4. Add following method into CustomWorkflowLocalServiceImpl 

/**
 * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 *
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 */

package com.custom.workflow.service.service.impl;

import com.custom.workflow.service.model.CustomWorkflow;
import com.custom.workflow.service.service.base.CustomWorkflowLocalServiceBaseImpl;
import com.liferay.portal.kernel.exception.PortalException;
import com.liferay.portal.kernel.exception.SystemException;
import com.liferay.portal.kernel.workflow.WorkflowConstants;
import com.liferay.portal.kernel.workflow.WorkflowHandlerRegistryUtil;
import com.liferay.portal.model.User;
import com.liferay.portal.service.ServiceContext;

/**
 * The implementation of the custom workflow 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.custom.workflow.service.service.CustomWorkflowLocalService}
 * 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 A0683741
 * @see com.custom.workflow.service.service.base.CustomWorkflowLocalServiceBaseImpl
 * @see com.custom.workflow.service.service.CustomWorkflowLocalServiceUtil
 */
public class CustomWorkflowLocalServiceImpl extends
CustomWorkflowLocalServiceBaseImpl {
/*
* NOTE FOR DEVELOPERS:
* Never reference this interface directly. Always use {@link
* com.custom.workflow.service.service.CustomWorkflowLocalServiceUtil} to
* access the custom workflow local service.
*/

public CustomWorkflow addCustomWorkflow(CustomWorkflow aCustomWorkflow,
long userId, ServiceContext serviceContext) throws SystemException,
PortalException {
CustomWorkflow customWorkflow = customWorkflowPersistence
.create(counterLocalService.increment(CustomWorkflow.class
.getName()));
customWorkflow.setCompanyId(aCustomWorkflow.getCompanyId());
customWorkflow.setGroupId(aCustomWorkflow.getGroupId());
customWorkflow.setCustomId(aCustomWorkflow.getCustomId());
customWorkflow.setUserId(serviceContext.getUserId());
customWorkflow.setStatus(WorkflowConstants.STATUS_DRAFT);
customWorkflow.setTitle(aCustomWorkflow.getTitle());
customWorkflowPersistence.update(customWorkflow, false);
assetEntryLocalService.updateEntry(userId, customWorkflow.getGroupId(),
CustomWorkflow.class.getName(), customWorkflow.getPrimaryKey(),
serviceContext.getAssetCategoryIds(),
serviceContext.getAssetTagNames());
WorkflowHandlerRegistryUtil.startWorkflowInstance(
customWorkflow.getCompanyId(), customWorkflow.getGroupId(),
userId, CustomWorkflow.class.getName(),
customWorkflow.getPrimaryKey(), customWorkflow, serviceContext);
return super.updateCustomWorkflow(aCustomWorkflow);
}

/*
* (non-Javadoc)
* @see
* com.custom.workflow.service.service.CustomWorkflowLocalService#CustomWorkflow
* (long, long, int, com.liferay.portal.service.ServiceContext)
*/
public CustomWorkflow updateStatus(long userId, long resourcePrimKey,
int status, ServiceContext serviceContext) throws PortalException,
SystemException {
User user = userLocalService.getUser(userId);
CustomWorkflow customWorkflow = getCustomWorkflow(resourcePrimKey);
customWorkflow.setStatus(status);
customWorkflow.setStatusByUserId(userId);
customWorkflow.setStatusByUserName(user.getFullName());
customWorkflow.setStatusDate(serviceContext.getModifiedDate());
customWorkflowPersistence.update(customWorkflow, false);
if (status == WorkflowConstants.STATUS_APPROVED) {
assetEntryLocalService.updateVisible(
CustomWorkflow.class.getName(), resourcePrimKey, true);
} else {
assetEntryLocalService.updateVisible(
CustomWorkflow.class.getName(), resourcePrimKey, false);
}
return customWorkflow;
}
}


5. Again build service.xml so that changes method should reflect into the local service util class

Now add following code into the CustomWorkflowPortlet class


package com.custom;

import com.custom.workflow.service.model.impl.CustomWorkflowImpl;
import com.custom.workflow.service.service.CustomWorkflowLocalServiceUtil;
import com.liferay.portal.kernel.exception.PortalException;
import com.liferay.portal.kernel.exception.SystemException;
import com.liferay.portal.kernel.util.ParamUtil;
import com.liferay.portal.kernel.util.WebKeys;
import com.liferay.portal.service.ServiceContext;
import com.liferay.portal.service.ServiceContextFactory;
import com.liferay.portal.theme.ThemeDisplay;
import com.liferay.util.bridges.mvc.MVCPortlet;

import java.io.IOException;

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

/**
 * Portlet implementation class CustomWorkflowPortlet
 */
public class CustomWorkflowPortlet extends MVCPortlet {
public void addCustomWorkflow(ActionRequest request, ActionResponse response) {
// do your required stuff
System.out.println("customId: "
+ ParamUtil.getInteger(request, "customId"));
System.out.println("title: " + ParamUtil.getString(request, "title"));
Long customerId = Long.valueOf(ParamUtil.getInteger(request,
"customId"));
String title = ParamUtil.getString(request, "title");
String renderURLVal =  ParamUtil.getString(request, "renderURLVal");
System.out.println("Render URL:"+renderURLVal);
System.out.println("customId: " + customerId);
System.out.println("title: " + title);
try {
workflowInitiation(request, response, customerId, title);
response.sendRedirect(renderURLVal);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (PortletException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

public void workflowInitiation(ActionRequest actionRequest,
ActionResponse actionResponse, long customId, String title)
throws IOException, PortletException {
// TODO Auto-generated method stub
ThemeDisplay themeDisplay = (ThemeDisplay) actionRequest
.getAttribute(WebKeys.THEME_DISPLAY);
System.out.println("Title : " + title);
CustomWorkflowImpl customWorkflow = new CustomWorkflowImpl();
customWorkflow.setTitle(title);
customWorkflow.setCustomId(customId);
customWorkflow.setCompanyId(themeDisplay.getCompanyId());
customWorkflow.setGroupId(themeDisplay.getScopeGroupId());
ThemeDisplay themeDisplay1 = (ThemeDisplay) actionRequest
.getAttribute(WebKeys.THEME_DISPLAY);
ServiceContext serviceContext;
try {
serviceContext = ServiceContextFactory.getInstance(
CustomWorkflowPortlet.class.getName(), actionRequest);
CustomWorkflowLocalServiceUtil.addCustomWorkflow(customWorkflow,
themeDisplay1.getUserId(), serviceContext);
} catch (PortalException e) {
e.printStackTrace();
} catch (SystemException e) {
e.printStackTrace();
}
}

}

6. Create a workflow handler CustomWorkflowPortlet as follows:

package com.custom.helper;
import com.custom.workflow.service.model.CustomWorkflow;
import com.custom.workflow.service.service.CustomWorkflowLocalServiceUtil;
import com.liferay.portal.kernel.exception.PortalException;
import com.liferay.portal.kernel.exception.SystemException;
import com.liferay.portal.kernel.language.LanguageUtil;
import com.liferay.portal.kernel.util.GetterUtil;
import com.liferay.portal.kernel.workflow.BaseWorkflowHandler;
import com.liferay.portal.kernel.workflow.WorkflowConstants;
import com.liferay.portal.service.ServiceContext;
import java.io.Serializable;
import java.util.Locale;
import java.util.Map;
public class CustomWorkflowHandler extends BaseWorkflowHandler
{
    public static final String CLASS_NAME = CustomWorkflow.class.getName();
    @Override
    public String getClassName()
    {
        return CLASS_NAME;
    }
    @Override
    public String getType(Locale locale)
    {
        return LanguageUtil.get(locale, "model.resource." + CLASS_NAME);
    }
    @Override
    public Object updateStatus(int status, Map<String, Serializable> workflowContext) throws PortalException,
            SystemException
    {
        long userId = GetterUtil.getLong((String) workflowContext.get(WorkflowConstants.CONTEXT_USER_ID));
        long resourcePrimKey = GetterUtil.getLong((String) workflowContext
                .get(WorkflowConstants.CONTEXT_ENTRY_CLASS_PK));
        ServiceContext serviceContext = (ServiceContext) workflowContext.get("serviceContext");
        return CustomWorkflowLocalServiceUtil.updateStatus(userId, resourcePrimKey, status, serviceContext);
    }
}


7. Once done the write following code into view.jsp file

<%@page import="com.liferay.portal.kernel.util.ListUtil"%>
<%@page import="com.custom.workflow.service.model.CustomWorkflow"%>
<%@page import="java.util.List"%>
<%@page
import="com.custom.workflow.service.service.CustomWorkflowLocalServiceUtil"%>
<%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet"%>
<%@taglib uri="http://liferay.com/tld/ui" prefix="liferay-ui"%>

<portlet:defineObjects />

<portlet:actionURL var="addCustomWorkflow" name="addCustomWorkflow" />
<portlet:renderURL var="renderURLVal" >
<portlet:param name="jspPage" value="/html/customworkflow/view.jsp"/>
</portlet:renderURL>
This is the
<b>Custom Workflow</b>
portlet in View mode.

<%
int totalCount = CustomWorkflowLocalServiceUtil
.getCustomWorkflowsCount();
out.println("Total count: " + totalCount);
List<CustomWorkflow> customWorkflowList = CustomWorkflowLocalServiceUtil
.getCustomWorkflows(0, totalCount);
%>

<form action="<%=addCustomWorkflow%>" method="post">
<input type="hidden" name="<portlet:namespace/>renderURLVal" value="<%=renderURLVal %>"/>
<input type="text" name="<portlet:namespace/>customId" /><br /> 
<input type="text" name="<portlet:namespace/>title" /><br /> 
<input type="submit" value="Save" />
</form>

<liferay-ui:search-container  delta="10" emptyResultsMessage="No Results Found">
         <liferay-ui:search-container-results total="<%= customWorkflowList.size() %>"
             results="<%= ListUtil.subList(customWorkflowList, searchContainer.getStart(), searchContainer.getEnd()) %>" />
         <liferay-ui:search-container-row modelVar="customWorkflow"
             className="com.custom.workflow.service.model.CustomWorkflow" >
             <%if(customWorkflow.getStatus()==0) {%>
             <liferay-ui:search-container-column-text name='Primary Key' property="primaryKey"  />
             <liferay-ui:search-container-column-text name='Custom Id' property="customId"  />
             <liferay-ui:search-container-column-text name='Title' property="title" />
             <liferay-ui:search-container-column-text name='Status' property="status"  />
                    <%} %>
        </liferay-ui:search-container-row>
        <liferay-ui:search-iterator searchContainer="<%= searchContainer %>" paginate="<%= true %>" />
    </liferay-ui:search-container>


8. Finally add entry of workflow code into liferay-portal.xml file to enable workflow from control panel:

<?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>CustomWorkflowPortlet</portlet-name>
<icon>/icon.png</icon>
<workflow-handler>com.custom.helper.CustomWorkflowHandler</workflow-handler>
<header-portlet-css>/css/main.css</header-portlet-css>
<footer-portlet-javascript>/js/main.js</footer-portlet-javascript>
<css-class-wrapper>CustomWorkflowPortlet-portlet</css-class-wrapper>
</portlet>
<portlet>
<portlet-name>custom-workflow</portlet-name>
<icon>/icon.png</icon>
<header-portlet-css>/css/main.css</header-portlet-css>
<footer-portlet-javascript>
/js/main.js
</footer-portlet-javascript>
<css-class-wrapper>custom-workflow-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>


Once everything done the deploy the portlet and 
9. Go to contorl panel -> configuration -> workflow -> Default Configuration

Select single level approver for CustomWorkflow Portlet 

10. Click on Save.

Once done the add the portlet on page and add the content

once content will add then will go to wofklow approver process, once approved then added list will be visible into the search-container list on the home page of custom workflow portlet.

Thanks!!

No comments: