Annotation are the replacement for traditional
XML configuration in the application development. Usually any application we
can see many xml configurations, which will have set of predefined tags. Server
containers or other application execution engines will use these XML configurations.
Example Spring Web Applications, we have many spring configuration files, which
will be used by Spring Containers to make the Dependency Injection among the
beans. Similarly, Liferay have many xml
configuration files while developing portlets. To manage the many XML files in the project is
little tedious so experts come up with Annotations
so that we can avoid most of the XML configurations while developing
applications.
OSGi
Declarative Services (DS) uses the XML
configurations to manage component dependency injection in the OSGi
Environment. To avoid old XML configuration, we have OSGi Declarative Services Annotations. Usage of annotation are very
simple and simply define in the java classes wherever it requires. All Annotation configurations finally turn
into XML configuration and this kind of action will be taking care by the
annotation implementation libraries. Developer do not need to worry about that
part.
Follow Liferay DXP/7 Tutorial to get more information.
Previous Articles have given more details
about XML configuration for the OSGi Components.
OSGi Declarative Service (DS) have
following are the important annotations to develop OSGi components.
@Component
@Reference
@Activate
@Deactivate
@Modified
|
Note:
All components are available in “org.osgi.service.component.annotations”
package.
@Component
@Component is very
important annotation in Declarative Services and it will make any simple java
class into OSGi component. Its class level annotation so the java class turn
into OSGi component.
Usually
the component have service implementation so we will use @Component annotation to make the services implementation java
class as Component to deliver services.
We can use @Component to any simple Java class in the OSGi component
development and all the components need not to have service implementation. We
can use @Component for any java
class in the OSGi bundle development.
When we declare java class as component
then the component registered in the Service Component Runtime registry so that
the component will be available to other component when it needed.
The @Component
have following attributes and all the attributes enclosed by braces. Each
attributes separated by comma.
The
following are the important attributes
name
immediate
service
property
|
Name:
Name uses to define the Component name.
Usually its fully qualified class name. This name will be uses as the reference
point for the other component.
Immediate:
Immediate
is Boolean type value, which tell the OSGi container to activate component
immediately when OSGi bundle deployed.
Service
Service
attribute is java service interface. Which tells that, for which service interface
the component is proving the implementation.
Property
If
component, needed any other configuration information we will provided as properties
and this will take list of key value pair values.
Note:
All the attributes are optional. As we
know, each component not necessary to provide the service implementation. Some
of them are service components and some of them are simple component, which
does not have any service implementation.
Case:
1
Simple
Component
When we use @Component it will turn into
as OSGi component.
Example
Component Java Class with @Component
package com.ls.ds.component;
import org.osgi.service.component.annotations.Component;
@Component
public class HelloComponent {
public HelloComponent() {
System.out.println("Hey
I am Simple OSGi Component");
}
}
|
Case:
2
Service
Component
As we know that usually component will
provide implementation for the services. Assume we have service interface and
have implementation class. Now we can make services implementation as component
with @Component annotation.
Example:
HelloService.java
package com.ls.ds.lsserviceprovider.services;
public interface HelloService {
public String greetHello();
}
|
HelloServiceImpl
Service Component
We will use @Component to service implementation class so that java class
became service component and these services will be available to other
components when it needed.
package com.ls.ds.lsserviceprovider.services.impl;
import
com.ls.de.lsserviceprovider.services.HelloService;
@Component(
name=com.ls.ds.lsserviceprovider.services.impl.HelloServiceImpl,
immediate = true,
service = HelloService.class
)
public class HelloServiceImpl implements HelloService {
@Override
public String greetHello() {
System.out.println("=====Inside
HelloServiceImpl.greetHello()=====");
return "Hello
Greeting from Liferay Savvy World..";
}
}
|
@Component
equivalent configuration for the above example as follows.
<?xml version="1.0"
encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0"
name="com.ls.ds.lsserviceprovider.services.impl.HelloServiceImpl">
<implementation class="com.ls.ds.lsserviceprovider.services.impl.HelloServiceImpl"
/>
<service>
<provide interface="com.ls.ds.lsserviceprovider.services.HelloService"
/>
</service>
</scr:component>
|
Case:
3
Service
Component with Properties
HelloService.java
package com.ls.ds.lsserviceprovider.services;
public interface HelloService {
public String greetHello();
}
|
HelloServiceImpl
Service Component
package com.ls.ds.lsserviceprovider.services.impl;
import
com.ls.de.lsserviceprovider.services.HelloService;
@Component(
name=com.ls.ds.lsserviceprovider.services.impl.HelloServiceImpl,
immediate = true,
property = {
"service.vendore=Liferay Savvy",
"service.description=Sample Hello Service",
},
service = HelloService.class
)
public class HelloServiceImpl implements HelloService {
@Override
public String greetHello() {
System.out.println("=====Inside
HelloServiceImpl.greetHello()=====");
return "Hello
Greeting from Liferay Savvy World..";
}
}
|
@Component
equivalent configuration for the above example as follows.
<?xml version="1.0"
encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0"
name="com.ls.ds.lsserviceprovider.services.impl.HelloServiceImpl">
<implementation
class="com.ls.ds.lsserviceprovider.services.impl.HelloServiceImpl"
/>
<property name="service.description" value="Sample Hello Service" />
<property name="service.vendor" value="Liferay Savvy" />
<service>
<provide interface="com.ls.ds.lsserviceprovider.services.HelloService"
/>
</service>
</scr:component>
|
Liferay
DXP/7 used the Declarative Services annotations
to develop Liferay Application modules such as portlets and hooks.
Liferay
Portlet Component
The following is simple example code for
the portlet component with @Component
Annotation
package com.liferay.polls.web.internal.portlet;
import com.liferay.polls.constants.PollsPortletKeys;
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.add-default-resource=true",
"com.liferay.portlet.css-class-wrapper=portlet-polls-display",
"com.liferay.portlet.display-category=category.cms",
"com.liferay.portlet.header-portlet-css=/css/main_polls_display.css",
"com.liferay.portlet.icon=/icons/polls_display.png",
"com.liferay.portlet.instanceable=true",
"com.liferay.portlet.preferences-owned-by-group=true",
"com.liferay.portlet.private-request-attributes=false",
"com.liferay.portlet.private-session-attributes=false",
"com.liferay.portlet.render-weight=50",
"com.liferay.portlet.scopeable=true",
"com.liferay.portlet.struts-path=polls_display",
"com.liferay.portlet.use-default-template=true",
"javax.portlet.display-name=Polls Display",
"javax.portlet.expiration-cache=0",
"javax.portlet.info.keywords=Polls",
"javax.portlet.info.short-title=Polls Display",
"javax.portlet.info.title=Polls Display",
"javax.portlet.init-param.template-path=/",
"javax.portlet.init-param.view-template=/polls_display/view.jsp",
"javax.portlet.name=" + PollsPortletKeys.POLLS_DISPLAY,
"javax.portlet.resource-bundle=content.Language",
"javax.portlet.security-role-ref=power-user,user",
"javax.portlet.supports.mime-type=text/html"
},
service = Portlet.class
)
public class PollsDisplayPortlet extends MVCPortlet {
}
|
@Reference
@Reference is opposite to @Component.
@Component is will used to declare java class as service component and
@Reference used to find the Service Component from the Service Component
Runtime Registry.
To identify the required service component
from the Service Registry we will use @Reference.
@Reference will identify the dependent component and inject into the current
component.
@Component is responsible to register the
component in the OSGi Service Registry and make it available to other components.
@Reference used to identify the right dependent
component and inject into the current component.
Example
@Reference
package com.ls.ds.consumer.component;
import com.ls.ds.lsserviceprovider.services.HelloService;
@Component(
name=com.ls.ds.ConsumerComponent
)
public class ConsumerComponent {
@Reference
public void setHelloService(HelloService helloService) {
System.out.println("=====Inside
Consumer Component setService()=====");
System.out.println(helloService.greetHello());
}
}
|
@Reference
equivalent configuration for the above example as follows.
<?xml version="1.0"
encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0"
name="com.ls.ds.ConsumerComponent">
<implementation class="com.ls.ds.ConsumerComponent" />
<reference bind="setHelloService" cardinality="1..1"
interface="com.ls.ds.lsserviceprovider.services.HelloService"
name="HelloService" policy="static" />
</scr:component>
|
The following are the important attributes
for the @Reference
target
Target attribute will used to filter the
reference components. Sometime we may have multiple implementation for service.
It means we have many Service Components with different implementation. To identify
the right Component instance, we will use target attribute. Usually we use set
of properties for Component declaration so same properties will be used
@Reference target to filter the reference components.
unbind
Unbind is used to declare setter method
when the component is unbind or dissociated with the component. When the
attribute with “-” it means there is
no setter method is called after component unbind.
Example:
@Reference(
target = "(javax.portlet.name=" +
NotificationsPortletKeys.NOTIFICATIONS + ")",
unbind = "-"
)
protected void setPanelApp(PanelApp panelApp) {
_panelApp = panelApp;
}
|
Liferay DXP/7 used the Declarative
Services annotations to develop Liferay Application modules such as portlets,
hooks.
Liferay
Portlet Component with @Reference
The following is simple example code for
the portlet component with @Reference
Annotation
@Component(
immediate = true,
property = {
"com.liferay.portlet.add-default-resource=true",
"com.liferay.portlet.css-class-wrapper=portlet-journal-content",
"com.liferay.portlet.display-category=category.cms",
"com.liferay.portlet.display-category=category.highlighted",
"com.liferay.portlet.header-portlet-css=/css/main.css",
"com.liferay.portlet.icon=/icons/journal_content.png",
"com.liferay.portlet.instanceable=true",
"com.liferay.portlet.layout-cacheable=true",
"com.liferay.portlet.preferences-owned-by-group=true",
"com.liferay.portlet.private-request-attributes=false",
"com.liferay.portlet.private-session-attributes=false",
"com.liferay.portlet.render-weight=50",
"com.liferay.portlet.scopeable=true",
"com.liferay.portlet.use-default-template=true",
"javax.portlet.display-name=Web Content Display",
"javax.portlet.expiration-cache=0",
"javax.portlet.init-param.template-path=/",
"javax.portlet.init-param.view-template=/view.jsp",
"javax.portlet.name=" + JournalContentPortletKeys.JOURNAL_CONTENT,
"javax.portlet.resource-bundle=content.Language",
"javax.portlet.security-role-ref=guest,power-user,user",
"javax.portlet.supports.mime-type=application/vnd.wap.xhtml+xml",
"javax.portlet.supports.mime-type=text/html"
},
service = Portlet.class
)
public class JournalContentPortlet extends MVCPortlet {
private ExportArticleUtil _exportArticleUtil;
private JournalArticleLocalService _journalArticleLocalService;
private JournalContent _journalContent;
private TrashEntryService _trashEntryService;
@Reference(unbind = "-")
protected void setExportArticleUtil(ExportArticleUtil exportArticleUtil) {
_exportArticleUtil = exportArticleUtil;
}
@Reference(unbind = "-")
protected void setJournalContent(JournalContent journalContent) {
_journalContent = journalContent;
}
@Reference(unbind = "-")
protected void setJournalContentSearchLocal(
JournalArticleLocalService
journalArticleLocalService) {
_journalArticleLocalService = journalArticleLocalService;
}
@Reference(unbind = "-")
protected void setTrashEntryService(TrashEntryService trashEntryService) {
_trashEntryService = trashEntryService;
}
protected void unsetExportArticleUtil(ExportArticleUtil exportArticleUtil) {
_exportArticleUtil = exportArticleUtil;
}
protected void unsetJournalContent(JournalContent journalContent) {
_journalContent = null;
}
protected void unsetJournalContentSearchLocal(
JournalArticleLocalService
journalArticleLocalService) {
_journalArticleLocalService = null;
}
@Override
public void doView(
RenderRequest
renderRequest, RenderResponse renderResponse)
throws IOException, PortletException {
..........
}
@Override
public void render(
RenderRequest
renderRequest, RenderResponse renderResponse)
throws IOException, PortletException {
............
}
public void restoreJournalArticle(
ActionRequest
actionRequest, ActionResponse actionResponse)
throws Exception {
.................
}
@Override
public void serveResource(
ResourceRequest
resourceRequest, ResourceResponse resourceResponse)
throws IOException, PortletException {
................
}
}
|
Component
Lifecycle Annotations
Each component have its own lifecycle and
each life cycle stage will call life cycle methods. To define these life cycle
methods we will use following annotation
@Activate
@Deactivate
@Modified
|
@Activate
@Activate will
define the method that will be called when the component is activated. When we
deploy the bundle then all the components will be activated.
The
activate method have 3 types of method signatures
@Activate
protected void activate() {
}
@Activate
protected void activate(Map<String, Object> properties) {
}
@Activate
protected void activate(BundleContext bundleContext, Map<String,
Object> properties) {
}
|
@Deactivate
@Deactivate will
define the method that will be called when the component is deactivated. Usually
when un-deploy or stop the bundle then the all component will be deactivated.
@Modified
@Modified
will define the method that will be called
when the component is modified.
Component
with Lifecycle Annotations
package com.ls.ds.consumer.component;
import com.ls.ds.lsserviceprovider.services.HelloService;
@Component(
name=com.ls.ds.ConsumerComponent
)
public class ConsumerComponent {
@Activate
public void activate() {
System.out.println("=====Service Component is Activated=====");
}
@Deactivate
public void @deactivate()
{
System.out.println("=====Service Component is Deactivated=====");
}
@Modified
public void modified() {
System.out.println("=====Service Component is Modified=====");
}
@Reference
public void setHelloService(HelloService helloService) {
System.out.println("=====Inside Consumer Component setService()=====");
System.out.println(helloService.greetHello());
}
}
|
Author