liferay (dxp) 7 tech meetup for developers
TRANSCRIPT
OSGi Overview
Portlets as Modules
Services as Modules
Extending Liferay DXP
What
Why
How
Why OSGi
Benefits of OSGi
• Reduced complexity• Reuse• Easy deployment• Dyanmic updates
What is OSGi
What is OSGi
OSGi (Open Service Gateway Initiative) is a Java framework for developing and deploying modular software programs and libraries. Each bundle is a tightly coupled, dynamically loadable collection of classes, jars, and configuration files that explicitly declare their external dependencies (if any).
How OSGi Works
Application / Bundles
Operating SystemHardware
JVMModules
Life cycleService Registry
Services
Secu
rity
How OSGi Works
How OSGi Works• Bundle• Bundle fragments• Bundle context
Sample Config. of bundleManifest-Version: 1.0 Bundle-Name: SimpleTestBundle Bundle-Activator: SimpleTestActivator Bundle-SymbolicName: SimpleTestBundle Bundle-Version: 1.0.0 Import-Package: org.azilen.framework; version=”1.3.1”
How OSGi Works• Bundles - static entities• Services - dynamics in OSGi
– Can appear, disappear at runtime according to a condition
• Service – Object, registered by a bundle
• BundleContext.registerService(iface, implementation, properties);
OSGi in Liferay
• Blade– JAVA Package manager– jpm install -f
https://releases.liferay.com/tools/blade-cli/latest/blade.jar
• Liferay workspace with Blade– blade init [WORKSPACE_NAME]
OSGi in Liferay
OSGi Overview
Portlets as Modules
Services as Modules
Extending Liferay DXP
Portlets as Modules
Modules as Portlets
MVC Portlet
Customize Portlet Configuration
Portlet Provider Template
MVC Portlet
• Create portlet structure using blade– blade create -t mvc-portlet -p com.azilen.app.mvcportlet -c SampleMvcPortlet sample-mvc-portlet-project
MVC Portlet
MVC Action Command@Component( immediate = true, property = { "javax.portlet.name=com_azilen_liferay_portlet_SampleMVCPortlet", "mvc.command.name=actionCommand1", "mvc.command.name=actionCommand2" }, service = MVCActionCommand.class ) public class DemoMVCActionCommand extends BaseMVCActionCommand { @Override protected void doProcessAction(ActionRequest req,
ActionResponse res) throws Exception { } }
MVC Portlet
@Component(
immediate = true,
property = {
"javax.portlet.name=com_azilen_liferay_portlet_SampleMVCPortlet",
"mvc.command.name=renderCommand1",
"mvc.command.name=renderCommand2"
},
service = MVCRenderCommand.class
)
public class DemoRenderCommand implements MVCRenderCommand {
@Override
public String render(RenderRequest req, RenderResponse res)
throws PortletException {
}
}
MVC Render Command
MVC Portlet
MVC Resource Command@Component( immediate = true, property = { "javax.portlet.name=com_azilen_liferay_portlet_SampleMVCPortlet", "mvc.command.name=ajax1", }, service = MVCResourceCommand.class ) public class DemoMVCResourceCommand extends BaseMVCResourceCommand { @Override protected void doServeResource(ResourceRequest res, ResourceResponse
res) throws Exception { } }
Customize Portlet Configuration
Create an interface to represent your config.
@Meta.OCD(id = "com.azilen.liferay.config.ChartConfig") public interface ChartConfig { public static final String FIELD_CHART_TITLE = "chartTitle";
@Meta.AD(required = false) public String getChartTitle(); }
Customize Portlet Configuration
Implement your configuration action class and add a reference to your configuration
@Component(
configurationPid = "com.azilen.liferay.config.ChartConfig",
configurationPolicy = ConfigurationPolicy.OPTIONAL,
immediate = true,
property = {
"javax.portlet.name=com_azilen_liferay_portlet_DemoConfigurationScreenPortlet"
},
service = ConfigurationAction.class
)
public class ChartConfigAction extends DefaultConfigurationAction {
}
Customize Portlet Configuration
• Implement the user interface for configuring your application
• -metatype: * in project bnd.bnd file– generate an XML configuration file
Portlet Provider Template
• Provide mechanism to customize existing entity behavior.– Portlet should be added in hidden category.
• Create a Java class – Extend BasePortletProvider class – Implement the appropriate portlet provider
interface– e.g. AddPortletProvider,ViewPortletProvider, BrowsePortletProvider.
Portlet Provider Template• Naming conventions
– Make sure that class name has suffix PortletProvider
• To override the default portlet with a custom portlet– Assign your portlet a higher service ranking. – Add in @Component declaration
• property= {"service.ranking:Integer=Integer.MAX_VALUE"}
Portlet Provider Template
Specify the methods you’d like to implement @Component( property = { "mod-el.class.name=com.liferay.document.library.kernel.model.DLFileEntry", "service.ranking:Integer=" + Integer.MAX_VALUE }, service = AddPortletProvider.class ) public class ProviderTemplateAddPortletProvider extends BasePortletProvider
implements AddPortletProvider { }
OSGi Overview
Portlets as Modules
Services as Modules
Extending Liferay DXP
Services as modules
Using Service Builder
Creating Service Wrappers
OSGi Services
Using Service Builder
• To create service builder modules :– blade create -t service-builder [-p packageName] projectName
e.g. blade create -t service-builder -p com.azilen.service.book book
– Above command will create two modules : book-api and book-service.
• To run service builder:– blade gw buildService
Using Service Builder
• Things Unchanged:– service.xml– Custom SQL– Dynamic Query– Finder methods– Model Hints– Adding new methods into EntityServiceImpl, EntityLocalServiceImpl,
EntityImpl
Using Service Builder
• Using service objects in portlet– @Reference– OSGi Injection
public class BookPortlet extends MVCPortlet { private BookLocalService bookLocalService; @Reference public void setBookLocalService(BookLocalService bookLocalService) { this.bookLocalService = bookLocalService; } … }
Creating Service Wrappers
• Override Liferay’s OOTB services• Service wrapper hooks in LR 6.2.• To create service wrapper module :
– blade create -t service-wrapper [-p packageName] [-c className] [-s serviceWrapperToExtend] projectName
– e.g. blade create -t service-wrapper -p com.azilen.serviceoverride -c CustomUserLocalService -s com.liferay.portal.kernel.service.UserLocalServiceWrapper service-override
Creating Service Wrappers@Component( immediate = true, property = { }, service = ServiceWrapper.class ) public class CustomUserLocalService extends UserLocalServiceWrapper { private static final Log _log =
LogFactoryUtil.getLog(CustomUserLocalService.class); public CustomUserLocalService() { super(null); } }
Creating Service Wrappers
• Override methods as required.@Override public int authenticateByEmailAddress(long companyId, String emailAddress,
String password, Map<String, String[]> headerMap, Map<String, String[]> parameterMap, Map<String, Object> resultsMap)
throws PortalException { // Custom logic _log.info("Custom Implementation of authenticateByEmailAddress()"); // Calling Liferay's default implementation of service return super.authenticateByEmailAddress(companyId, emailAddress,
password, headerMap, parameterMap, resultsMap); }
OSGi services
• OSGi Services can be registered with Activatorpublic class CalcServiceActivator implements BundleActivator { private ServiceRegistration<CalcService> reg; @Override public void start(BundleContext bundleContext) throws Exception {
reg = bundleContext.registerService(CalcService.class, new CalcServiceImpl(), null);
} @Override public void stop(BundleContext bundleContext) throws Exception { reg.unregister(); } }
OSGi services
• Injecting OSGi Services in portlets
• Null check before using service object
public class CalcPortlet extends MVCPortlet {
private CalcService _calcService;
@Reference
public void setCalcService(CalcService calcService) {
this._calcService = calcService;
} …
}
OSGi Overview
Portlets as Modules
Services as Modules
Extending Liferay DXP
Extending Liferay DXP
Fragments
• Extension of host module• Uses same classloader as host module• Extending out of box modules based on
requirements• Earlier versions used Hook plugins• Create a Liferay fragment
– blade create -t fragment [-h hostBundleName] [-H hostBundleVersion] projectName
Customize Existing JSP
Override Language properties
Add Servlet Filter
Add Custom event
Customize Existing JSP• Override Liferay Login module
– blade create -t fragment -h com.liferay.login.web -H 1.0.7 login-fragment-module
• Find host module symbolic name and version – Connect to gogo shell using
• telnet localhost 11311– 219 ACTIVE com.liferay.login.web_1.0.7
Customizing existing JSP
• copy jsp from Liferay-src/modules/apps/foundation/login/login-web/src/main/resources/META-INF/resources/login.jsp
and paste it in login-fragment-
src/main/resources/META-INF/resources/.
Override Language Properties
• Want to change Login portlet authentication failed message– authentication-failed key
• blade create -t mvc-portlet -p com.azilen.fragment.language -c CustomLanguageComponent language-fragment-module
Override Language Properties @Component( property = { "language.id=en_US" }, service = ResourceBundle.class ) public class CustomLanguageComponent extends ResourceBundle { ResourceBundle bundle = ResourceBundle.getBundle("content.Language", UTF8Control.INSTANCE); @Override protected Object handleGetObject(String key) { return bundle.getObject(key); } @Override public Enumeration<String> getKeys() { return bundle.getKeys(); } }
Override Language Properties
• Create Language_en.properties under /language-fragment-module/src/main/resources/content
• Add authentication-failed language key with custom message.– authentication-failed=Authentication failed. Make sure you entered correct username and password.
Add Servlet Filter
• Used for intercepting http request• Extend BaseFilter class• e.g. Intercept every request and print log
Add Servlet Filter
@Component(
immediate = true,
property = {
"dispatcher=REQUEST", "dispatcher=FORWARD",
"servlet-context-name=",
"servlet-filter-name=Custom Filter",
"url-pattern=/*"
},
service = Filter.class
)
public class CustomFilter extends BaseFilter {
private static final Log _log = LogFactoryUtil.getLog(CustomFilter.class);
@Override
protected void processFilter(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain)
throws Exception {
_log.info("Intercepted request : " + request);
filterChain.doFilter(request, response);
}
}
Add Custom Event
• com.liferay.portal.kernel.events.LifecycleAction is one of the extension points that can be leveraged by service template
• Create a new module using “service” template– e.g., blade create –t service –p com.azilen.training.lifecycle.loginpostaction –c CustomLoginPostAction –s com.liferay.portal.kernel.events.LifecycleAction login-post-action
Add Custom Event
@Component( property = { "key=login.events.post" }, service = LifecycleAction.class ) public class CustomLoginPostAction implements LifecycleAction { private static final Log _log =
LogFactoryUtil.getLog(CustomLoginPostAction.class); @Override public void processLifecycleEvent(LifecycleEvent lifecycleEvent)
throws ActionException { HttpServletRequest request = lifecycleEvent.getRequest(); User user = null; try { user = PortalUtil.getUser(request); } catch (PortalException e) { _log.error(e); } … } }
Add Custom Event
• Apart from this lifecycle event, there are many other such portal lifecycle events supported like:login.events.post, logout.events.post, logout.events.pre, global.shutdown.events, global.startup.events, application.shutdown.events, application.startup.events
OSGi Overview
Portlets as Modules
Services as Modules
Extending Liferay DXP
Thank You
Q&A
@AzilenTech #AzilenTechMeetup
www.azilen.com/kb/liferay-dxp/