首页 > 代码库 > 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‘);});});
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>
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);}
===================
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;}
===================
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);}
===================
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);}
===================
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集成开发