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 Annotationsso 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.
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 @Componenthave 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.."; } } |
@Componentequivalent 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.."; } } |
@Componentequivalent 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 @ComponentAnnotation
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()); } } |
@Referenceequivalent 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 unbind |
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 @ReferenceAnnotation
@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
0 comments:
Post a Comment