首页 > 代码库 > Liferay7 BPM门户开发之37: Liferay7下的OSGi Hook集成开发

Liferay7 BPM门户开发之37: Liferay7下的OSGi Hook集成开发

hook开发是Liferay客制扩展的一种方式,比插件灵活,即可以扩展liferay门户,也能对原有特性进行更改,Liferay有许多内置的服务,比如用hook甚至可以覆盖Liferay服务。

可作为系统服务挂钩(Liferay Service Hook),还有其他类型的hook...

Liferay6.2 时的hook开发比较有限,而在Liferay7则大为不同,OSGi services的彻底改进至Liferay的底层模型框架,使得Liferay可以支持更多的定制扩展!
OSGi plugins可以快速部署到Liferay,就和其他类型的插件一样。

名词:

FQPN: a fully qualified portlet name

 

正在不断整理完善中...

PollerProcessor

com.liferay.portal.kernel.poller.PollerProcessor
集成点:"javax.portlet.name" : a FQPN
用途: 轮训消息机制,用于类似Ajax在页面显示信息
例子:
JS:

技术分享
AUI().use(‘aui-base‘,‘aui-delayed-task‘,    ‘liferay-poller‘,function(A) {Liferay.namespace(‘BladePoller‘);Liferay.BladePoller.Manager = {init: function() {var instance = this;instance._portletId = A.one("#pollerPortletId").val();instance._bladePollerContainer = A.one(‘#bladePollerContainer‘);console.log("Init: portletId:"+instance._portletId+", containerId:"+instance._bladePollerContainer);instance._updateTask = new A.debounce(instance._updateMessage,30000,instance);instance._updateTask.delay(0);Liferay.Poller.addListener(instance._portletId,instance._onPollerUpdate, instance);Liferay.on(‘sessionExpired‘,function(event) {Liferay.Poller.removeListener(instance._portletId);instance._bladePollerContainer.hide();});},send: function(options, id) {console.log("Options:" + options + ", id:" + id);var instance = this;Liferay.Poller.submitRequest(instance._portletId, options, id);instance._updateTask();},_updateMessage: function() {console.log("Update Message");var instance = this;instance.send(    {status : ‘OK‘});},_onPollerUpdate : function(response, chunkId) {console.log("updating...");var instance = this;instance._bladePollerContainer.text(response.content.message);instance._bladePollerContainer.show();instance.send({status : ‘OK‘});}};A.augment(Liferay.BladePoller.Manager, A.Attribute, true);Liferay.publish(‘pollerPortletReady‘,{defaultFn: A.bind(‘init‘, Liferay.BladePoller.Manager),fireOnce: true});A.on(‘domready‘,function() {Liferay.fire(‘pollerPortletReady‘);});});
View Code

jsp:

技术分享
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %><%@ 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/theme" prefix="liferay-theme" %><%@taglib uri="http://liferay.com/tld/ui" prefix="liferay-ui" %><liferay-theme:defineObjects /><portlet:defineObjects /><p><b><liferay-ui:messagekey="blade_portlet_BladePollProcessorPortlet.title" /></b></p><input id="pollerPortletId" type="hidden" value="<%= portletDisplay.getId() %>" /><p id="bladePollerContainer"></p>
View Code

 

Java:

技术分享
import com.liferay.portal.kernel.portlet.bridges.mvc.MVCPortlet;import javax.portlet.Portlet;import org.osgi.service.component.annotations.Component;@Component(immediate = true,property = {"com.liferay.portlet.css-class-wrapper=portlet-pollprocessor-blade","com.liferay.portlet.display-category=category.sample","com.liferay.portlet.header-portlet-javascript=/js/main.js","com.liferay.portlet.poller-processor-class=blade.portlet.BladePollProcessor","com.liferay.portlet.private-request-attributes=false","com.liferay.portlet.private-session-attributes=false","com.liferay.portlet.remoteable=true","com.liferay.portlet.render-weight=50","javax.portlet.display-name=BLADE PollProcessor","javax.portlet.expiration-cache=0","javax.portlet.init-param.template-path=/","javax.portlet.init-param.view-template=/view.jsp","javax.portlet.portlet.info.keywords=blade,pollprocessor","javax.portlet.portlet.info.short-title=BLADE PollProcessor","javax.portlet.portlet.info.title=BLADE PollProcessor","javax.portlet.resource-bundle=content.Language","javax.portlet.security-role-ref=power-user,user"},service = Portlet.class)public class BladePollProcessorPortlet extends MVCPortlet {}import com.liferay.portal.kernel.json.JSONFactoryUtil;import com.liferay.portal.kernel.json.JSONObject;import com.liferay.portal.kernel.log.Log;import com.liferay.portal.kernel.log.LogFactoryUtil;import com.liferay.portal.kernel.poller.BasePollerProcessor;import com.liferay.portal.kernel.poller.DefaultPollerResponse;import com.liferay.portal.kernel.poller.PollerProcessor;import com.liferay.portal.kernel.poller.PollerRequest;import com.liferay.portal.kernel.poller.PollerResponse;import java.util.Date;import org.osgi.service.component.annotations.Component;@Component(immediate = true,property = {"javax.portlet.name=blade_portlet_BladePollProcessorPortlet"},service = PollerProcessor.class)public class BladePollProcessor extends BasePollerProcessor {@Overrideprotected PollerResponse doReceive(PollerRequest pollerRequest)throws Exception {if (_log.isDebugEnabled()) {_log.debug("Recevied the poller request" + pollerRequest);}JSONObject responseJSON = JSONFactoryUtil.createJSONObject();PollerResponse pollerResponse = new DefaultPollerResponse();responseJSON.put("message", "Hello from BLADE Poller, time now is:" + new Date());pollerResponse.setParameter("content", responseJSON);return pollerResponse;}@Overrideprotected void doSend(PollerRequest pollerRequest) throws Exception {String status = getString(pollerRequest, "status");if (_log.isInfoEnabled()) {_log.info("Poller status:" + status);}}private final Log _log = LogFactoryUtil.getLog(BladePollProcessor.class);}
View Code

 

===================

AuthFailure & Authenticator

com.liferay.portal.security.auth.AuthFailure
集成点:"key" : "auth.failure" | "auth.max.failures"
用途: 用户登录失败处理

com.liferay.portal.security.auth.Authenticator
集成点:"key" : "auth.pipeline.post" | "auth.pipeline.post"
用途: 用户登录验证
例子:

Liferay7 BPM门户开发之32: 实现自定义认证登陆(定制Authentication Hook)


===================


StrutsAction & StrutsPortletAction


com.liferay.portal.kernel.struts.StrutsAction
集成点:"path" : a struts path (starting with "/portal")
用途: HttpServletRequest方式的Struts Action跳转

com.liferay.portal.kernel.struts.StrutsPortletAction
集成点:"path" : a portlet struts path
用途: StrutsPortletAction方式的Struts Action跳转

StrutsAction和StrutsPortletAction都不是官方推荐方式

例子:

技术分享
@Component(    immediate = true, property = {"path=/login/login"},    service = StrutsPortletAction.class)public class BladePortletAction extends BaseStrutsPortletAction {    @Override    public void processAction(            StrutsPortletAction originalStrutsPortletAction,            PortletConfig portletConfig, ActionRequest actionRequest,            ActionResponse actionResponse)        throws Exception {        if (_log.isDebugEnabled()) {            _log.debug("BladePortletAction - procesAction");        }        ThemeDisplay themeDisplay = (ThemeDisplay)actionRequest.getAttribute(            WebKeys.THEME_DISPLAY);        User loggedinUser = themeDisplay.getUser();        if ((loggedinUser != null) && _log.isInfoEnabled()) {            _log.info(                "Logging in with user:[" + loggedinUser.getFirstName() + " " +                    loggedinUser.getLastName() + "]");            _log.info(                "Logged in user: Current Greetings[" +                    loggedinUser.getGreeting() + "]");        }        originalStrutsPortletAction.processAction(            originalStrutsPortletAction, portletConfig, actionRequest,            actionResponse);    }    @Override    public String render(            StrutsPortletAction originalStrutsPortletAction,            PortletConfig portletConfig, RenderRequest renderRequest,            RenderResponse renderResponse)        throws Exception {        if (_log.isDebugEnabled()) {            _log.debug("BladePortletAction - render");        }        ThemeDisplay themeDisplay = (ThemeDisplay)renderRequest.getAttribute(            WebKeys.THEME_DISPLAY);        User loggedinUser = themeDisplay.getUser();        if (loggedinUser != null) {            loggedinUser.setLastName("BLADE");            loggedinUser.setGreeting(                "Hello," + loggedinUser.getFirstName() + " from BLADE!");            _userLocalService.updateUser(loggedinUser);        }        return originalStrutsPortletAction.render(            originalStrutsPortletAction, portletConfig, renderRequest,            renderResponse);    }    @Override    public void serveResource(            StrutsPortletAction originalStrutsPortletAction,            PortletConfig portletConfig, ResourceRequest resourceRequest,            ResourceResponse resourceResponse)        throws Exception {        if (_log.isDebugEnabled()) {            _log.debug("BladePortletAction - serveResource");        }        originalStrutsPortletAction.serveResource(            originalStrutsPortletAction, portletConfig, resourceRequest,            resourceResponse);    }    @Reference(unbind = "-")    public void setUserService(UserLocalService userService) {        _userLocalService = userService;    }    private static final Log _log = LogFactoryUtil.getLog(        BladePortletAction.class);    private UserLocalService _userLocalService;}
View Code

 

===================

ResourceBundle


java.util.ResourceBundle
集成点:"javax.portlet.name" : a FQPN
用途: 用于国际化字符串
例子:https://dev.liferay.com/develop/tutorials/-/knowledge_base/7-0/localizing-your-application

demo:

技术分享
import com.liferay.portal.kernel.language.UTF8Control;import java.util.Enumeration;import java.util.ResourceBundle;import org.osgi.service.component.annotations.Component;@Component(    immediate = true, property = {"language.id=en_US"},    service = ResourceBundle.class)public class CustomResourceBundle extends ResourceBundle {    @Override    public Enumeration<String> getKeys() {        return _resourceBundle.getKeys();    }    @Override    protected Object handleGetObject(String key) {        return _resourceBundle.getObject(key);    }    private final ResourceBundle _resourceBundle = ResourceBundle.getBundle(        "content.Language", UTF8Control.INSTANCE);}
View Code

 

===================

ActionCommand

com.liferay.util.bridges.mvc.ActionCommand
集成点:"action.command.name" : an MVCPortlet action command name
集成点:"javax.portlet.name" : a FQPN
用途: Action周期处理

定义:https://docs.liferay.com/portal/7.0/javadocs/portal-kernel/com/liferay/portal/kernel/portlet/bridges/mvc/BaseMVCActionCommand.html#doProcessAction(javax.portlet.ActionRequest,%20javax.portlet.ActionResponse))

例子:https://dev.liferay.com/develop/tutorials/-/knowledge_base/7-0/mvc-action-command

demo:

技术分享
@Component(    immediate = true,    property = {        "javax.portlet.name=com_liferay_blade_samples_portlet_actioncommand_GreeterPortlet",        "mvc.command.name=greet"    },    service = MVCActionCommand.class)public class GreeterActionCommand implements MVCActionCommand {    @Override    public boolean processAction(            ActionRequest actionRequest, ActionResponse actionResponse)        throws PortletException {        _handleActionCommand(actionRequest);        return true;    }    private void _handleActionCommand(ActionRequest actionRequest) {        String name = ParamUtil.get(actionRequest, "name", StringPool.BLANK);        if (_log.isInfoEnabled()) {            _log.info("Hello " + name);        }        String greetingMessage = "Hello " + name + "! Welcome to OSGi";        actionRequest.setAttribute("GREETER_MESSAGE", greetingMessage);        SessionMessages.add(actionRequest, "greetingMessage", greetingMessage);    }    private static final Log _log = LogFactoryUtil.getLog(        GreeterActionCommand.class);}
View Code

 

===================

Filter

javax.portlet.filter.ActionFilter

javax.portlet.filter.EventFilter

javax.portlet.filter.RenderFilter

javax.portlet.filter.ResourceFilter

集成点:"javax.portlet.name" : a FQPN

例子:

Liferay7 BPM门户开发之36: 使用Portlet filters过滤器做切面AOP

 

===================

Social

com.liferay.portlet.social.model.SocialActivityInterpreter
集成点:"javax.portlet.name" : a FQPN
用途: 
例子:

com.liferay.portlet.social.model.SocialRequestInterpreter
集成点:"javax.portlet.name" : a FQPN
用途: 
例子:

===================

AssetRendererFactory

com.liferay.portlet.asset.model.AssetRendererFactory
集成点:"javax.portlet.name" : a FQPN
用途:
例子:

===================

AtomCollectionAdapter

com.liferay.portal.kernel.atom.AtomCollectionAdapter<?>
集成点:"javax.portlet.name" : a FQPN
用途:
例子:

===================

ConfigurationAction

com.liferay.portal.kernel.portlet.ConfigurationAction
集成点:"javax.portlet.name" : a FQPN
用途: 配置动作扩展
例子:https://dev.liferay.com/develop/tutorials/-/knowledge_base/7-0/implementing-configuration-actions

===================

ControlPanelEntry

com.liferay.portlet.ControlPanelEntry
集成点:"javax.portlet.name" : a FQPN
用途:
例子:

===================

CustomAttributesDisplay

com.liferay.portlet.expando.model.CustomAttributesDisplay
集成点:"javax.portlet.name" : a FQPN
用途:
例子:

===================

com.liferay.portlet.dynamicdatamapping.util.DDMDisplay
集成点:"javax.portlet.name" : a FQPN
用途:
例子:

===================

com.liferay.portal.kernel.portlet.FriendlyURLMapper
集成点:"javax.portlet.name" : a FQPN
用途:
例子:

===================

com.liferay.portal.kernel.search.Indexer
集成点:"javax.portlet.name" : a FQPN
用途:
例子:

===================

com.liferay.portal.kernel.search.OpenSearch
集成点:"javax.portlet.name" : a FQPN
用途:
例子:

===================

com.liferay.portal.security.permission.PermissionPropagator
集成点:"javax.portlet.name" : a FQPN
用途:
例子:

===================

com.liferay.portal.kernel.pop.MessageListener
集成点:"javax.portlet.name" : a FQPN
用途:
例子:

===================

com.liferay.portal.kernel.lar.PortletDataHandler
集成点:"javax.portlet.name" : a FQPN
用途:
例子:

===================

com.liferay.portal.kernel.portlet.PortletLayoutListener
集成点:"javax.portlet.name" : a FQPN
用途:
例子:

===================

javax.portlet.PreferencesValidator
集成点:"javax.portlet.name" : a FQPN
用途:
例子:

===================

com.liferay.portal.kernel.lar.StagedModelDataHandler
集成点:"javax.portlet.name" : a FQPN
用途:
例子:

===================

com.liferay.portal.kernel.template.TemplateHandler
集成点:"javax.portlet.name" : a FQPN
用途:
例子:

===================

com.liferay.portal.kernel.trash.TrashHandler
集成点:"javax.portlet.name" : a FQPN
用途:
例子:

===================

com.liferay.portal.kernel.servlet.URLEncoder
集成点:"javax.portlet.name" : a FQPN
用途:
例子:

===================

com.liferay.portal.kernel.notifications.UserNotificationHandler
集成点:"javax.portlet.name" : a FQPN
用途:
例子:

===================

com.liferay.portal.kernel.webdav.WebDAVStorage
集成点:"javax.portlet.name" : a FQPN
用途:
例子:

===================

com.liferay.portal.kernel.workflow.WorkflowHandler
集成点:"javax.portlet.name" : a FQPN
用途:
例子:

===================

com.liferay.portal.kernel.xmlrpc.Method
集成点:"javax.portlet.name" : a FQPN
用途:
例子:

 

===================

com.liferay.portal.kernel.events.LifecycleAction
集成点:
用途:
例子:

 

===================

com.liferay.portal.kernel.search.IndexerPostProcessor
集成点: "indexer.class.name" : a indexer or entity class name
用途:
例子:

 

===================

com.liferay.portal.service.ServiceWrapper
集成点:
用途:
例子:

 

待续...

Liferay7 BPM门户开发之37: Liferay7下的OSGi Hook集成开发