OSGi Overview provides information on OSGi, its benefits, and how it works. Key points include:
- OSGi allows developing modular Java programs through bundles that declare dependencies. Each bundle dynamically loads classes.
- In Liferay, bundles become portlets, services, or extensions. The blade CLI helps create these.
- Portlets can be implemented as MVC portlets or use configuration and portlet provider templates.
- Services can be created with Service Builder or wrapped. OSGi services can also be registered.
- Liferay modules can be extended through fragments to customize JSPs, properties, add filters or events.
7. 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).
12. 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);
22. 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();
}
23. 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_DemoConfigurationScreen
Portlet"
},
service = ConfigurationAction.class
)
public class ChartConfigAction extends DefaultConfigurationAction {
}
24. Customize Portlet Configuration
• Implement the user interface for configuring
your application
• -metatype: * in project bnd.bnd file
– generate an XML configuration file
25. 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.
26. 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"}
27. Portlet Provider Template
Specify the methods you’d like to implement
@Component(
property = {
"mod-
el.class.name=com.liferay.document.library.kernel.model.DLF
ileEntry",
"service.ranking:Integer=" + Integer.MAX_VALUE
},
service = AddPortletProvider.class
)
public class ProviderTemplateAddPortletProvider
extends BasePortletProvider
implements AddPortletProvider {
}
31. 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
33. • Things Unchanged:
– service.xml
– Custom SQL
– Dynamic Query
– Finder methods
– Model Hints
– Adding new methods into EntityServiceImpl, EntityLocalServiceImpl,
EntityImpl
34. 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;
}
…
}
35. 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.UserLocalServ
iceWrapper service-override
36. 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);
}
}
37. 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);
}
38. OSGi services
• OSGi Services can be registered with Activator
public 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();
}
}
39. 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;
}
…
}
42. 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
44. 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
45. 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/.
47. 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();
}
}
48. 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.
49. Add Servlet Filter
• Used for intercepting http request
• Extend BaseFilter class
• e.g. Intercept every request and print log
51. Add Custom Event
• com.liferay.portal.kernel.events.Lif
ecycleAction 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.loginpost
action –c CustomLoginPostAction –s
com.liferay.portal.kernel.events.Lifecy
cleAction login-post-action
52. 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);
}
…
}
}
53. 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